build: one page holds every need that answers a record; runs: the kommune planned again by Opus

Two needs about the same record wrote the same page, and the last won.
The record's page now holds one form per answering need, under
words["forms"][need].

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GT37Z1Xtfd9pUuQtMTg6Yt
This commit is contained in:
Bendik Aagaard Lynghaug
2026-09-30 08:58:55 +02:00
co-authored by Claude Fable 5.1
parent 9776dc1808
commit 3dabcf7c58
58 changed files with 8713 additions and 37 deletions
+43
View File
@@ -0,0 +1,43 @@
# Vestmark kommune, planned again by Opus after the September additions
`portal-trainer plan --intake intakes/building-permits.yaml --personas
intakes/building-permits-personas.yaml --llm "MODEL=opus EFFORT=medium
engines/claude.sh" --rounds 3`, on 2026-09-30, after the guidance
learnt to name records that answer records (`about`), members-only
needs (`door` + `enters_as`), a group contact, and `grants` as the
moment of membership. The plan came out of round 1 and passed the
builder's checks; rounds 2 and 3 were not needed.
Side by side with the hand-written `plans/building-permits.yaml`
(2026-09-25, before any of those existed):
| | hand-written | Opus, this run |
|---|---|---|
| needs / groups / doors | 14 / 5 / 2 | 14 / 4 / 2 |
| needs `about` another | – | 3: objection, appeal, exemption, all about the application |
| `grants` | – | firm approval lists the firm in `approved_firms` |
| members-only (`door` + `enters_as`) | – | 3: a firm's application, completion certificate, temporary permission, for `approved_firms` |
| `deadlines` | – | 4, incl. the six-week hearing |
| public lists | 6 | 3 |
| `reached_from` | 3 | 3 |
So the new lines were taken up unprompted, and for the right things: an
objection belongs to the application it objects to, and a firm files
because it was approved. What Opus did not carry over from the intake:
the counter's own needs (`log-counter-enquiry`, `case-status-enquiry`),
which two personas name; and the external agencies as a group of their
own, folded into the case officers instead.
## What the run found in the tools
- **The builder wrote one answer page per answering need**, at the
same path, so with three needs about the application only the last
survived and iris found no path for the others. A record's page now
holds one form per need about it (`words[...]["forms"][need]`).
- **iris counted the carried record id as effort.** An objection form
that carries the application's id was one field over its budget.
iris main (with portal v0.5.7) counts what a person fills in.
With both fixed the site lints clean but for the two personas above:
37 questions, 15 aggregates, 225 access rules, 12 of 14 needs met.
Not built with words, not deployed.
@@ -0,0 +1,289 @@
# plan.yaml
A plan is a needs spec that also says what each form collects. A
builder turns it into a working site with no further decisions, so
every structural fact about the business has to be in it.
```yaml
business: <name>
language: en # the intake's language code
contact: { name: <who answers for the site>, email: <their email> }
about: >
What the business does, in its own words.
mail: { from: "<name> <post@their-domain>", reply_to: <their inbox> }
# who every mail the site sends comes from; required as soon
# as any need has `mails`
does: # the front door's first card: what the business does, one
- id: kebab-case # or two features, one role each, no button. Say it for the
for: <need id> # role the business exists for and the next one it serves.
text: what it does for them, in the intake's own words
shows: # what the site shows as it is: a live figure, the latest
- id: kebab-case # releases, what has been built; `resource` is portal's block
text: one line on what it is
resource: { public: true, source: { kind: url, url: https://... } }
doors: # a first question before the forms, only when the offers
- id: kebab-case # are more than one page holds (measured: four doors beat
who: who comes through it # ten offers on one page; six offers on one page beat doors)
groups: # groups with a label the public may see: the committees
- { id: traffic, label: Traffic, invited_by: [board] } # a person can ask to join (optional; label defaults to the id)
invites_by: [board] # groups whose desk may invite people into every desk
needs:
- id: kebab-case # ASCII only
who: the kind of person, in plain words, in the intake's language
wants: what they want from the business
door: <door id> # the door this public need sits behind; omit to put it on the front door
enters_as: <group> # ONLY for a role inside the business; omit for the public
lands_in: <bucket> # snake_case, ASCII
handled_by: <group> # the role that must see and move the record
stages: [open, <stage>, ..., <end>, <end>]
# EVERY stage the business said a case goes through, first to
# last, read off their own sentences one verb at a time: "they
# come in, we go and look, we send a quote, we win or lose it"
# is [open, surveyed, quoted, won, lost]. A pipeline is not an
# inbox: "answered" is rarely the real outcome.
done_when: [<end>, <end>] # every stage that counts as finished, good or bad
success: [<end>] # the finished stages that are a good outcome for the business
skippable: [<stage>] # stages a case may pass over (papers already complete)
requires: <one sentence> # what the person must ALREADY have or be for this to work:
# a membership, a reference number, the link from a mail, an
# account. Stated on the card above the form. Omit when there
# is none; never invent one
turned_down_from: [open, <stage>]
# the unfinished stages a case can still be turned down from;
# omit for every one. An applicant is declined before they
# start, not after - after, they depart
reached_from: { <stage>: [<stage>, ...] }
# where a stage is entered from, when the line does not say it.
# Two things need it and nothing else does: a case SENT BACK to
# a stage it was already past ("papers missing" again, after the
# hearing turned something up), and a GOOD ENDING partway along,
# where a case finishes well without walking to the end ("we
# changed our own decision", instead of passing it upwards).
# A stage named here is entered from exactly those stages and
# nowhere else, so it also says where a refusal may NOT come
# from. Omit unless the business described one of those two
moves_by: { <stage>: [<group>, ...] }
# only where someone other than handled_by moves a case INTO a
# stage: another group, or `submitter` (the person who sent the
# form; the form must then collect a required `email`)
watched_by: [<group>] # groups that see these cases and move nothing; `public` opens a
# read-only page of the bucket to everyone (contact details hidden)
mails: { open: submitter, <end>: submitter, <stage>: <address> }
# who hears when a case enters a stage: `submitter` (the form
# must then collect a required `email`) or one address. Tell the
# person on arrival and on every decision that is about them.
grants: { <stage>: <group> }
# a stage that makes the person a member of a group when their
# case arrives (an approval that IS membership); the form must
# then collect a required `name` and a required `email`
deadlines: { <stage>: { days: 30, to: <stage> } }
# a stage a clock moves on from when a case sits in it that long
# (a notice that expires, a hearing with no answer); only along
# a move the stages already allow
public_states: [<stage>] # with `public` in watched_by: the stages the public list shows
# (a noticeboard shows what is up, not what was taken down)
stages_text: { open: <words>, <stage>: <words> }
# each stage in the intake's language, where the ASCII id
# would read wrong to a person: "ikke_lost" is "ikke løst"
events: { open: applied } # ONLY when rebuilding a live site: the event names its
# aggregates.yaml already has, so its records keep replaying
attended_by: > # ONLY for a stage no desk button moves: the automation that does
what moves it, in a sentence
max_fields: 4 # decide this BEFORE writing collects, from what the intake
# says about the person; a budget that equals the form's size
# is counted, not decided, and is reported as such
# how many required fields THIS person will tolerate, from what
# the intake says about them: someone on a phone with gloves
# on gets 3, a first enquiry 4 to 6, a firm's paperwork 5 to 6
collects: # the form; name is snake_case ASCII, type one of
# text (default), email, tel, textarea, date, select, location
# (a pin on a map, stored as lat/lon/zoom; optional: true,
# since a map needs a browser that can draw one)
- { name: name }
- { name: phone, type: tel }
- { name: problem, type: textarea }
- { name: urgency, type: select, options: [This week, This month, No rush] }
- { name: can_do, type: select, multiple: true, options: [Drive, Cook, Carry] } # any number
- { name: committee, type: select, options_from: groups } # the labelled groups above
- { name: address, optional: true, private: true } # never on a public page
```
What a portal site can do - use what serves this business, leave the
rest. Each is one line in the plan, and the builder does the wiring:
- **Show, not only ask.** A bucket with `watched_by: [public]` becomes
a public list: its newest few records sit inline on the front door,
linked to the whole list, contact details pruned. What neighbours
reported and where it stands, which changes were approved, what is
on the noticeboard: a visitor who sees the place working trusts it,
and a person who reported something sees it being dealt with.
`public_states` shows only the stages worth showing.
- **Stay in dialogue.** `mails` tells the person at the stages that
are about them, and a reply to that mail comes back to the case as
a note. `moves_by: { <stage>: [submitter] }` gives them a move of
their own through their link: confirm, withdraw, say it is solved.
- **Let a decision do the work.** `grants` makes an approval into
membership: the person gets an account and a place in the group the
moment the case gets there; `deadlines` lets a stage end on its own
(a notice that expires, a request nobody took up); `invites_by` lets
a desk bring a person in without anyone touching an admin tool.
- **Let one record answer another.** A need `about` another need is
one answer per record of it, from that record's own row on the
public list: a neighbour saying "I can lend you that" to a notice, a
bid to a request. `mails: { open: owner }` sends the answer straight
to whoever posted the record, and the site keeps no queue - the
poster's inbox is the queue. The site never becomes a go-between.
- **Keep some things for members.** A need with `door` and `enters_as`
is offered to everyone on the door and taken on the group's page
behind sign-in, with name and address filled from the account: a
seat on a committee for members, a discount for customers. The
group is one a decision `grants`, so nobody has to be waved in.
- **Answer for the pages as a group.** `contact: { name, email, group }`
makes the contact a group's inbox rather than a person: no account
is made for it, and every member of the group may suggest changes
to the pages from the page itself.
- **Make the choices real.** `groups` with labels, and a select with
`options_from: groups`, so a form offers exactly the committees or
teams that exist; `multiple: true` where a person can pick several.
- **Place things.** A `location` field puts a pin on a map (where the
hazard is, where the job is), when the site has maps.
- **Open with the business itself.** `does` says what it does for the
roles it exists for; `shows` puts its live content beside that.
Rules:
- One need per (kind of person, thing they want). Work inside the
business counts: a role recording or posting something is a need
with `enters_as`. The intake's "what slows us down" usually names one.
- Groups are the roles the intake names, as snake_case identifiers.
- The front door opens with `does` (at most two features, one role
each) and `shows`, then holds at most seven offers: doors plus needs
with no door. A door with no need behind it is refused; a door on a
need with `enters_as` is the way to the members' page. A role `does`
speaks for must have a move
of its own after sending (`moves_by` with `submitter`) or a public
view, or it is a spectator.
- Every need whose form collects an email should tell the person on
arrival and on the decisions about them (`mails`); the plan then
needs `mail: { from }`.
- Every feature on a card explains itself: a list says what one row is
and what its buttons do, a form says what to have ready. If an
alternative only works for someone who already has something, say so
in `requires` - a condition the reader meets only after filling the
form in has already cost them the filling in.
- Needs that land in the same bucket must have the same stages,
done_when, skippable, moves_by, watched_by and handled_by.
- Every required field is one the business will use to act on the
record. If the intake gives no reason to need it, make it optional or
leave it out. The required fields must not exceed max_fields.
- Only `select` lists `options`, and it must list them.
- Everything a person reads (who, wants, about, select options) is in
the intake's language. Everything a machine reads (ids, buckets,
groups, stages, field names) is plain ASCII: no æ, ø, å.
- Write no personas.
# Task
A business filled in this intake. Write its plan.yaml: every need the intake implies, for the public and for each role inside the business, with the stages read off how the business says things progress, the form each need collects, and how much each person will tolerate.
## Intake
# A building authority's intake: the hardest sector the trainer has
# been given. Cases that pause and resume, cases that belong to other
# cases, a decision two roles sign, a deadline nobody in the building
# controls, and an appeal that reopens something already finished.
# Written the way the department head would write it, in plain words.
business: Vestmark kommune - Building and Planning
contact: { name: Solveig Hauge, email: byggesak@vestmark.example }
language: en
what_we_do: >
We are the building authority for a municipality of twenty-one
thousand people. Anyone who wants to build, demolish, divide a
property or change what a building is used for has to come to us
first. We check the drawings against the zoning map and the building
regulations, we let the neighbours and the other authorities have
their say, and then we approve or refuse. We also decide exemptions
from the zoning rules, we inspect what is actually built, we sign off
finished work, and we deal with building that was never applied for.
who_comes_to_us: >
Homeowners who want a garage, an extension or a new window, and who
have never read a regulation in their life. Architects and
engineering firms who file on behalf of owners; they have to be
approved by us before they may file anything. Neighbours who got a
notice in the post and do not agree with what is planned next door.
The other authorities we are obliged to ask: the road authority, the
fire service, the heritage office, the county. People who ring to say
something is going up behind their fence without permission. And
anyone who wants to sit down with us before they spend eighty
thousand on drawings.
what_we_keep_track_of: >
Pre-application meetings: someone asks for one, we find a time, we
meet, and we write down what we told them so they can hold us to it.
Applications: they arrive, someone checks whether the papers are all
there, and if something is missing we write and ask for it, and the
twelve-week clock stops until they answer. Often we have to ask
twice. When it is complete we send it out to the neighbours and to
the agencies and wait six weeks. Then a case officer writes a
recommendation, and the head of section signs the decision: approved,
approved with conditions, or refused. People can withdraw at any
point, and quite a few do once they hear from the neighbours.
Exemptions: if what someone wants breaks the zoning rules they can
ask for an exemption. It rides along with the application but it is a
decision of its own, and we are not allowed to grant one before the
county has been asked.
Objections: a neighbour who got a notice writes to us within the
hearing period. Each objection belongs to an application. We register
it, the applicant gets to answer it, and the case officer has to
address every single one in the decision, by name.
Hearing answers: we ask an agency, they answer, or they do not, and
when the deadline has passed we go on without them.
Appeals: for three weeks after a decision anyone with an interest can
appeal it. We go through it ourselves first, and if we change our own
mind that is the end of it. If we do not, it goes to the appeals
board, who meet once a month and either uphold us or overturn us.
Inspections: we pick cases and go and look, on site. Either it is as
approved, or we write up what is wrong and set a date for it to be
put right, and then we go back.
Finishing: when the work is done the firm asks for a completion
certificate. If they want to move in before everything is done they
can ask for a temporary permission instead. We check what was
inspected and what is still outstanding before we sign anything.
Illegal building: someone reports it, we go and look, we write to the
owner and they have to explain themselves, and then they either apply
for it properly, take it down, or we fine them weekly until they do.
Approved firms: a firm sends us their registration, their insurance
and what they are qualified for, we check it, and then they are on
the list and may file applications.
who_is_involved: >
The front desk logs what comes in over the counter and on the phone,
and keeps the archive. Four case officers carry the cases. The head
of section signs every decision and every exemption; a case officer
may not sign their own. Two inspectors are out on site most of the
week and write up what they find on a phone in a cold wind. The
appeals board is seven elected politicians who meet on the third
Tuesday of the month and read what we send them. The agencies are
outside the building altogether and only ever answer hearings. The
approved firms file applications and answer objections on behalf of
their clients.
what_slows_us_down: >
The twelve-week clock, and the fact that stopping it and starting it
again is done by hand in a spreadsheet. Applications that arrive
missing half the drawings. Objections that come in on paper and get
stapled to the wrong case. Neighbours ringing to ask what is
happening with the case behind their house, which we are obliged to
tell them and which takes ten minutes every time. Agencies that never
answer at all. And nobody outside this building can see a case
without asking us for it.
Reply with the YAML only, no prose, no code fences.
@@ -0,0 +1,423 @@
business: Vestmark kommune - Building and Planning
language: en
contact: { name: Solveig Hauge, email: byggesak@vestmark.example }
about: >
We are the building authority for a municipality of twenty-one
thousand people. Anyone who wants to build, demolish, divide a
property or change what a building is used for has to come to us
first. We check the drawings against the zoning map and the building
regulations, we let the neighbours and the other authorities have
their say, and then we approve or refuse. We also decide exemptions
from the zoning rules, we inspect what is actually built, we sign off
finished work, and we deal with building that was never applied for.
mail: { from: "Vestmark kommune Building and Planning <post@vestmark.example>", reply_to: byggesak@vestmark.example }
does:
- id: check-and-decide
for: application
text: >
We check your drawings against the zoning map and the building
regulations, let the neighbours and the other authorities have
their say, and then approve or refuse. You can follow your case
here the whole way.
- id: firms-file-here
for: firm-application
text: >
Approved firms file applications for their clients here, see what
is missing and ask for the completion certificate when the work is done.
doors:
- id: build
who: You want to build, demolish, divide a property or change what a building is used for
- id: neighbour
who: Something is planned or going up next door to you
- id: firm
who: You are an architect or an engineering firm filing on behalf of owners
invites_by: [head_of_section]
needs:
- id: pre-application-meeting
who: Anyone who wants to sit down with us before they spend money on drawings
wants: A meeting with a case officer, and a written note of what we told them
door: build
lands_in: pre_application_meetings
handled_by: case_officers
stages: [open, scheduled, met, written_up, cancelled]
done_when: [written_up, cancelled]
success: [written_up]
turned_down_from: [open, scheduled]
moves_by: { cancelled: [submitter, case_officers] }
watched_by: [front_desk]
mails: { open: submitter, scheduled: submitter, written_up: submitter, cancelled: submitter }
stages_text: { open: asked for, scheduled: time found, met: meeting held, written_up: written down and sent, cancelled: cancelled }
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: property_address }
- { name: what_you_plan, type: textarea }
- { name: phone, type: tel, optional: true }
- { name: place, type: location, optional: true }
- id: application
who: A homeowner who wants a garage, an extension, a new window or another change to their property
wants: Permission to build, demolish, divide a property or change what a building is used for
door: build
lands_in: applications
handled_by: case_officers
stages: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused, withdrawn]
done_when: [approved, approved_with_conditions, refused, withdrawn]
success: [approved, approved_with_conditions]
skippable: [papers_missing, papers_received]
reached_from:
papers_missing: [open, papers_received, complete, in_hearing]
refused: [recommended]
moves_by:
papers_received: [submitter]
approved: [head_of_section]
approved_with_conditions: [head_of_section]
refused: [head_of_section]
withdrawn: [submitter, case_officers]
watched_by: [public, front_desk, inspectors]
public_states: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused]
mails:
open: submitter
papers_missing: submitter
complete: submitter
in_hearing: submitter
approved: submitter
approved_with_conditions: submitter
refused: submitter
withdrawn: submitter
deadlines: { in_hearing: { days: 42, to: hearing_over } }
stages_text:
open: received
papers_missing: papers missing, clock stopped
papers_received: missing papers sent in
complete: complete, clock running
in_hearing: out to neighbours and agencies
hearing_over: hearing over
recommended: recommendation written
approved: approved
approved_with_conditions: approved with conditions
refused: refused
withdrawn: withdrawn
max_fields: 5
collects:
- { name: name, private: true }
- { name: email, type: email, private: true }
- { name: property_address }
- { name: kind_of_work, type: select, options: [New building, Extension, Garage or outbuilding, Window or facade change, Demolition, Dividing a property, Change of use] }
- { name: what_you_want_to_do, type: textarea }
- { name: enclosed, type: select, multiple: true, optional: true, options: [Site plan, Floor plans, Elevations, Section drawing, Neighbour notices sent, Statement from the owner] }
- { name: phone, type: tel, optional: true, private: true }
- { name: place, type: location, optional: true }
- id: firm-application
who: An approved architect or engineering firm filing on behalf of an owner
wants: To file a building application for a client and see what is missing
door: firm
enters_as: approved_firms
requires: Your firm must be on our list of approved firms before it may file anything.
lands_in: applications
handled_by: case_officers
stages: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused, withdrawn]
done_when: [approved, approved_with_conditions, refused, withdrawn]
success: [approved, approved_with_conditions]
skippable: [papers_missing, papers_received]
reached_from:
papers_missing: [open, papers_received, complete, in_hearing]
refused: [recommended]
moves_by:
papers_received: [submitter]
approved: [head_of_section]
approved_with_conditions: [head_of_section]
refused: [head_of_section]
withdrawn: [submitter, case_officers]
watched_by: [public, front_desk, inspectors]
public_states: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused]
mails:
open: submitter
papers_missing: submitter
complete: submitter
in_hearing: submitter
approved: submitter
approved_with_conditions: submitter
refused: submitter
withdrawn: submitter
deadlines: { in_hearing: { days: 42, to: hearing_over } }
stages_text:
open: received
papers_missing: papers missing, clock stopped
papers_received: missing papers sent in
complete: complete, clock running
in_hearing: out to neighbours and agencies
hearing_over: hearing over
recommended: recommendation written
approved: approved
approved_with_conditions: approved with conditions
refused: refused
withdrawn: withdrawn
max_fields: 6
collects:
- { name: name, private: true }
- { name: email, type: email, private: true }
- { name: property_address }
- { name: kind_of_work, type: select, options: [New building, Extension, Garage or outbuilding, Window or facade change, Demolition, Dividing a property, Change of use] }
- { name: what_you_want_to_do, type: textarea }
- { name: enclosed, type: select, multiple: true, options: [Site plan, Floor plans, Elevations, Section drawing, Neighbour notices sent, Statement from the owner] }
- { name: owner_name, optional: true, private: true }
- { name: phone, type: tel, optional: true, private: true }
- { name: place, type: location, optional: true }
- id: exemption
who: An applicant whose plans break the zoning rules
wants: An exemption from the zoning rules, decided alongside their application
door: build
about: application
requires: An application with us; the exemption rides along with it and is asked for from its row on the list of cases.
lands_in: exemptions
handled_by: case_officers
stages: [open, county_asked, county_heard, granted, refused]
done_when: [granted, refused]
success: [granted]
moves_by: { granted: [head_of_section], refused: [head_of_section] }
watched_by: [front_desk]
mails: { open: submitter, county_asked: submitter, granted: submitter, refused: submitter }
deadlines: { county_asked: { days: 42, to: county_heard } }
stages_text: { open: received, county_asked: county asked, county_heard: county has answered or its deadline has passed, granted: granted, refused: refused }
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: rule_it_breaks }
- { name: why_it_should_be_allowed, type: textarea }
- id: objection
who: A neighbour who got a notice in the post and does not agree with what is planned next door
wants: To object to an application and have the objection answered in the decision
door: neighbour
about: application
requires: The application must still be out for hearing; objections are taken until the six weeks are up.
lands_in: objections
handled_by: case_officers
stages: [open, registered, answered, addressed]
done_when: [addressed]
success: [addressed]
skippable: [answered]
moves_by: { registered: [front_desk, case_officers], answered: [approved_firms, case_officers] }
watched_by: [front_desk, head_of_section]
mails: { open: submitter, registered: owner, addressed: submitter }
stages_text: { open: received, registered: registered on the case, answered: answered by the applicant, addressed: addressed in the decision }
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: your_property }
- { name: objection, type: textarea }
- { name: phone, type: tel, optional: true }
- id: logged-objection
who: The front desk, when an objection comes in on paper or over the counter
wants: To put the objection on the right case straight away
enters_as: front_desk
about: application
lands_in: objections
handled_by: case_officers
stages: [open, registered, answered, addressed]
done_when: [addressed]
success: [addressed]
skippable: [answered]
moves_by: { registered: [front_desk, case_officers], answered: [approved_firms, case_officers] }
watched_by: [front_desk, head_of_section]
mails: { registered: owner }
stages_text: { open: received, registered: registered on the case, answered: answered by the applicant, addressed: addressed in the decision }
max_fields: 4
collects:
- { name: name }
- { name: your_property }
- { name: objection, type: textarea }
- { name: received_on, type: date }
- { name: phone, type: tel, optional: true }
- id: hearing-request
who: A case officer who is obliged to ask another authority about an application
wants: To ask the road authority, the fire service, the heritage office or the county, and go on when the deadline has passed
enters_as: case_officers
about: application
lands_in: hearing_answers
handled_by: case_officers
stages: [open, answered, no_answer]
done_when: [answered, no_answer]
success: [answered]
moves_by: { answered: [agencies, case_officers] }
watched_by: [agencies, front_desk]
deadlines: { open: { days: 42, to: no_answer } }
stages_text: { open: asked, answered: answered, no_answer: deadline passed without an answer }
max_fields: 3
collects:
- { name: agency, type: select, options: [Road authority, Fire service, Heritage office, County] }
- { name: what_we_ask, type: textarea }
- { name: answer_by, type: date }
- id: appeal
who: Anyone with an interest in a decision, the applicant or a neighbour
wants: To appeal a decision we have made
about: application
requires: A decision on the application, made no more than three weeks ago.
lands_in: appeals
handled_by: case_officers
stages: [open, under_review, decision_changed, sent_to_board, upheld, overturned, dismissed]
done_when: [decision_changed, upheld, overturned, dismissed]
success: [decision_changed, upheld, overturned]
turned_down_from: [open, under_review]
reached_from: { decision_changed: [under_review] }
moves_by: { decision_changed: [head_of_section], upheld: [appeals_board], overturned: [appeals_board] }
watched_by: [appeals_board, head_of_section, front_desk]
mails: { open: submitter, decision_changed: submitter, sent_to_board: submitter, upheld: submitter, overturned: submitter, dismissed: submitter }
stages_text: { open: received, under_review: we are going through it ourselves, decision_changed: we changed our own decision, sent_to_board: sent to the appeals board, upheld: decision upheld by the board, overturned: decision overturned by the board, dismissed: dismissed }
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: your_interest, type: select, options: [I am the applicant, I am a neighbour, Other] }
- { name: grounds, type: textarea }
- { name: phone, type: tel, optional: true }
- id: illegal-building-report
who: Someone who sees something going up behind their fence without permission
wants: To tell us, so that we go and look
door: neighbour
lands_in: illegal_building
handled_by: case_officers
stages: [open, inspected, owner_written_to, explained, fined, applied_for, taken_down, nothing_illegal]
done_when: [applied_for, taken_down, nothing_illegal]
success: [applied_for, taken_down]
skippable: [fined]
turned_down_from: [open, inspected, explained]
moves_by: { inspected: [inspectors], fined: [head_of_section] }
watched_by: [front_desk, inspectors]
stages_text: { open: reported, inspected: we have been and looked, owner_written_to: owner written to, explained: owner has explained, fined: weekly fine running, applied_for: applied for properly, taken_down: taken down, nothing_illegal: nothing illegal found }
max_fields: 3
collects:
- { name: where }
- { name: what_is_being_built, type: textarea }
- { name: place, type: location, optional: true }
- { name: name, optional: true, private: true }
- { name: phone, type: tel, optional: true, private: true }
- id: logged-report
who: The front desk, when someone rings or comes in about building without permission
wants: To log the report so an inspector goes and looks
enters_as: front_desk
lands_in: illegal_building
handled_by: case_officers
stages: [open, inspected, owner_written_to, explained, fined, applied_for, taken_down, nothing_illegal]
done_when: [applied_for, taken_down, nothing_illegal]
success: [applied_for, taken_down]
skippable: [fined]
turned_down_from: [open, inspected, explained]
moves_by: { inspected: [inspectors], fined: [head_of_section] }
watched_by: [front_desk, inspectors]
stages_text: { open: reported, inspected: we have been and looked, owner_written_to: owner written to, explained: owner has explained, fined: weekly fine running, applied_for: applied for properly, taken_down: taken down, nothing_illegal: nothing illegal found }
max_fields: 3
collects:
- { name: where }
- { name: what_is_being_built, type: textarea }
- { name: place, type: location, optional: true }
- { name: name, optional: true, private: true }
- { name: phone, type: tel, optional: true, private: true }
- id: inspection
who: An inspector on site, writing on a phone in a cold wind
wants: To write up what was found on a case and set a date for what must be put right
enters_as: inspectors
about: application
lands_in: inspections
handled_by: inspectors
stages: [open, to_put_right, as_approved]
done_when: [as_approved]
success: [as_approved]
skippable: [to_put_right]
watched_by: [case_officers, head_of_section]
stages_text: { open: inspected, to_put_right: to be put right, then we go back, as_approved: as approved }
max_fields: 2
collects:
- { name: finding, type: select, options: [As approved, Something is wrong] }
- { name: what_is_wrong, type: textarea, optional: true }
- { name: put_right_by, type: date, optional: true }
- { name: place, type: location, optional: true }
- id: completion-certificate
who: An approved firm whose work on a case is done
wants: A completion certificate for the finished work
door: firm
enters_as: approved_firms
about: application
requires: Your firm must be on our list of approved firms, and the application must be approved.
lands_in: completion_certificates
handled_by: case_officers
stages: [open, checked, issued, refused]
done_when: [issued, refused]
success: [issued]
moves_by: { issued: [head_of_section], refused: [head_of_section] }
watched_by: [inspectors, front_desk]
mails: { open: submitter, issued: submitter, refused: submitter }
stages_text: { open: asked for, checked: inspections and outstanding work checked, issued: certificate signed, refused: refused }
max_fields: 5
collects:
- { name: name }
- { name: email, type: email }
- { name: finished_on, type: date }
- { name: what_was_built, type: textarea }
- { name: still_outstanding, type: textarea, optional: true }
- id: temporary-permission
who: An approved firm whose client wants to move in before everything is done
wants: A temporary permission to use the building
door: firm
enters_as: approved_firms
about: application
requires: Your firm must be on our list of approved firms, and the application must be approved.
lands_in: temporary_permissions
handled_by: case_officers
stages: [open, checked, issued, refused]
done_when: [issued, refused]
success: [issued]
moves_by: { issued: [head_of_section], refused: [head_of_section] }
watched_by: [inspectors, front_desk]
mails: { open: submitter, issued: submitter, refused: submitter }
stages_text: { open: asked for, checked: inspections and outstanding work checked, issued: temporary permission signed, refused: refused }
max_fields: 6
collects:
- { name: name }
- { name: email, type: email }
- { name: move_in_on, type: date }
- { name: still_outstanding, type: textarea }
- { name: finished_by, type: date }
- id: firm-approval
who: An architect or engineering firm that wants to file applications for owners
wants: To be approved by us and put on the list of firms that may file
door: firm
lands_in: approved_firm_requests
handled_by: case_officers
stages: [open, checked, listed, refused]
done_when: [listed, refused]
success: [listed]
moves_by: { listed: [head_of_section], refused: [head_of_section] }
watched_by: [public, front_desk]
public_states: [listed]
mails: { open: submitter, listed: submitter, refused: submitter }
grants: { listed: approved_firms }
stages_text: { open: received, checked: registration, insurance and qualifications checked, listed: on the list, refused: refused }
max_fields: 6
collects:
- { name: firm }
- { name: name, private: true }
- { name: email, type: email, private: true }
- { name: registration_number }
- { name: insurance, private: true }
- { name: qualified_for, type: select, multiple: true, options: [Applying on behalf of owners, Architectural design, Structural engineering, Fire safety design, Geotechnical engineering, Carrying out the work, Independent control] }
- { name: phone, type: tel, optional: true, private: true }
@@ -0,0 +1,721 @@
# plan.yaml
A plan is a needs spec that also says what each form collects. A
builder turns it into a working site with no further decisions, so
every structural fact about the business has to be in it.
```yaml
business: <name>
language: en # the intake's language code
contact: { name: <who answers for the site>, email: <their email> }
about: >
What the business does, in its own words.
mail: { from: "<name> <post@their-domain>", reply_to: <their inbox> }
# who every mail the site sends comes from; required as soon
# as any need has `mails`
does: # the front door's first card: what the business does, one
- id: kebab-case # or two features, one role each, no button. Say it for the
for: <need id> # role the business exists for and the next one it serves.
text: what it does for them, in the intake's own words
shows: # what the site shows as it is: a live figure, the latest
- id: kebab-case # releases, what has been built; `resource` is portal's block
text: one line on what it is
resource: { public: true, source: { kind: url, url: https://... } }
doors: # a first question before the forms, only when the offers
- id: kebab-case # are more than one page holds (measured: four doors beat
who: who comes through it # ten offers on one page; six offers on one page beat doors)
groups: # groups with a label the public may see: the committees
- { id: traffic, label: Traffic, invited_by: [board] } # a person can ask to join (optional; label defaults to the id)
invites_by: [board] # groups whose desk may invite people into every desk
needs:
- id: kebab-case # ASCII only
who: the kind of person, in plain words, in the intake's language
wants: what they want from the business
door: <door id> # the door this public need sits behind; omit to put it on the front door
enters_as: <group> # ONLY for a role inside the business; omit for the public
lands_in: <bucket> # snake_case, ASCII
handled_by: <group> # the role that must see and move the record
stages: [open, <stage>, ..., <end>, <end>]
# EVERY stage the business said a case goes through, first to
# last, read off their own sentences one verb at a time: "they
# come in, we go and look, we send a quote, we win or lose it"
# is [open, surveyed, quoted, won, lost]. A pipeline is not an
# inbox: "answered" is rarely the real outcome.
done_when: [<end>, <end>] # every stage that counts as finished, good or bad
success: [<end>] # the finished stages that are a good outcome for the business
skippable: [<stage>] # stages a case may pass over (papers already complete)
requires: <one sentence> # what the person must ALREADY have or be for this to work:
# a membership, a reference number, the link from a mail, an
# account. Stated on the card above the form. Omit when there
# is none; never invent one
turned_down_from: [open, <stage>]
# the unfinished stages a case can still be turned down from;
# omit for every one. An applicant is declined before they
# start, not after - after, they depart
reached_from: { <stage>: [<stage>, ...] }
# where a stage is entered from, when the line does not say it.
# Two things need it and nothing else does: a case SENT BACK to
# a stage it was already past ("papers missing" again, after the
# hearing turned something up), and a GOOD ENDING partway along,
# where a case finishes well without walking to the end ("we
# changed our own decision", instead of passing it upwards).
# A stage named here is entered from exactly those stages and
# nowhere else, so it also says where a refusal may NOT come
# from. Omit unless the business described one of those two
moves_by: { <stage>: [<group>, ...] }
# only where someone other than handled_by moves a case INTO a
# stage: another group, or `submitter` (the person who sent the
# form; the form must then collect a required `email`)
watched_by: [<group>] # groups that see these cases and move nothing; `public` opens a
# read-only page of the bucket to everyone (contact details hidden)
mails: { open: submitter, <end>: submitter, <stage>: <address> }
# who hears when a case enters a stage: `submitter` (the form
# must then collect a required `email`) or one address. Tell the
# person on arrival and on every decision that is about them.
grants: { <stage>: <group> }
# a stage that makes the person a member of a group when their
# case arrives (an approval that IS membership); the form must
# then collect a required `name` and a required `email`
deadlines: { <stage>: { days: 30, to: <stage> } }
# a stage a clock moves on from when a case sits in it that long
# (a notice that expires, a hearing with no answer); only along
# a move the stages already allow
public_states: [<stage>] # with `public` in watched_by: the stages the public list shows
# (a noticeboard shows what is up, not what was taken down)
stages_text: { open: <words>, <stage>: <words> }
# each stage in the intake's language, where the ASCII id
# would read wrong to a person: "ikke_lost" is "ikke løst"
events: { open: applied } # ONLY when rebuilding a live site: the event names its
# aggregates.yaml already has, so its records keep replaying
attended_by: > # ONLY for a stage no desk button moves: the automation that does
what moves it, in a sentence
max_fields: 4 # decide this BEFORE writing collects, from what the intake
# says about the person; a budget that equals the form's size
# is counted, not decided, and is reported as such
# how many required fields THIS person will tolerate, from what
# the intake says about them: someone on a phone with gloves
# on gets 3, a first enquiry 4 to 6, a firm's paperwork 5 to 6
collects: # the form; name is snake_case ASCII, type one of
# text (default), email, tel, textarea, date, select, location
# (a pin on a map, stored as lat/lon/zoom; optional: true,
# since a map needs a browser that can draw one)
- { name: name }
- { name: phone, type: tel }
- { name: problem, type: textarea }
- { name: urgency, type: select, options: [This week, This month, No rush] }
- { name: can_do, type: select, multiple: true, options: [Drive, Cook, Carry] } # any number
- { name: committee, type: select, options_from: groups } # the labelled groups above
- { name: address, optional: true, private: true } # never on a public page
```
What a portal site can do - use what serves this business, leave the
rest. Each is one line in the plan, and the builder does the wiring:
- **Show, not only ask.** A bucket with `watched_by: [public]` becomes
a public list: its newest few records sit inline on the front door,
linked to the whole list, contact details pruned. What neighbours
reported and where it stands, which changes were approved, what is
on the noticeboard: a visitor who sees the place working trusts it,
and a person who reported something sees it being dealt with.
`public_states` shows only the stages worth showing.
- **Stay in dialogue.** `mails` tells the person at the stages that
are about them, and a reply to that mail comes back to the case as
a note. `moves_by: { <stage>: [submitter] }` gives them a move of
their own through their link: confirm, withdraw, say it is solved.
- **Let a decision do the work.** `grants` makes an approval into
membership: the person gets an account and a place in the group the
moment the case gets there; `deadlines` lets a stage end on its own
(a notice that expires, a request nobody took up); `invites_by` lets
a desk bring a person in without anyone touching an admin tool.
- **Let one record answer another.** A need `about` another need is
one answer per record of it, from that record's own row on the
public list: a neighbour saying "I can lend you that" to a notice, a
bid to a request. `mails: { open: owner }` sends the answer straight
to whoever posted the record, and the site keeps no queue - the
poster's inbox is the queue. The site never becomes a go-between.
- **Keep some things for members.** A need with `door` and `enters_as`
is offered to everyone on the door and taken on the group's page
behind sign-in, with name and address filled from the account: a
seat on a committee for members, a discount for customers. The
group is one a decision `grants`, so nobody has to be waved in.
- **Answer for the pages as a group.** `contact: { name, email, group }`
makes the contact a group's inbox rather than a person: no account
is made for it, and every member of the group may suggest changes
to the pages from the page itself.
- **Make the choices real.** `groups` with labels, and a select with
`options_from: groups`, so a form offers exactly the committees or
teams that exist; `multiple: true` where a person can pick several.
- **Place things.** A `location` field puts a pin on a map (where the
hazard is, where the job is), when the site has maps.
- **Open with the business itself.** `does` says what it does for the
roles it exists for; `shows` puts its live content beside that.
Rules:
- One need per (kind of person, thing they want). Work inside the
business counts: a role recording or posting something is a need
with `enters_as`. The intake's "what slows us down" usually names one.
- Groups are the roles the intake names, as snake_case identifiers.
- The front door opens with `does` (at most two features, one role
each) and `shows`, then holds at most seven offers: doors plus needs
with no door. A door with no need behind it is refused; a door on a
need with `enters_as` is the way to the members' page. A role `does`
speaks for must have a move
of its own after sending (`moves_by` with `submitter`) or a public
view, or it is a spectator.
- Every need whose form collects an email should tell the person on
arrival and on the decisions about them (`mails`); the plan then
needs `mail: { from }`.
- Every feature on a card explains itself: a list says what one row is
and what its buttons do, a form says what to have ready. If an
alternative only works for someone who already has something, say so
in `requires` - a condition the reader meets only after filling the
form in has already cost them the filling in.
- Needs that land in the same bucket must have the same stages,
done_when, skippable, moves_by, watched_by and handled_by.
- Every required field is one the business will use to act on the
record. If the intake gives no reason to need it, make it optional or
leave it out. The required fields must not exceed max_fields.
- Only `select` lists `options`, and it must list them.
- Everything a person reads (who, wants, about, select options) is in
the intake's language. Everything a machine reads (ids, buckets,
groups, stages, field names) is plain ASCII: no æ, ø, å.
- Write no personas.
# Task
A business filled in this intake. Write its plan.yaml: every need the intake implies, for the public and for each role inside the business, with the stages read off how the business says things progress, the form each need collects, and how much each person will tolerate.
## Intake
# A building authority's intake: the hardest sector the trainer has
# been given. Cases that pause and resume, cases that belong to other
# cases, a decision two roles sign, a deadline nobody in the building
# controls, and an appeal that reopens something already finished.
# Written the way the department head would write it, in plain words.
business: Vestmark kommune - Building and Planning
contact: { name: Solveig Hauge, email: byggesak@vestmark.example }
language: en
what_we_do: >
We are the building authority for a municipality of twenty-one
thousand people. Anyone who wants to build, demolish, divide a
property or change what a building is used for has to come to us
first. We check the drawings against the zoning map and the building
regulations, we let the neighbours and the other authorities have
their say, and then we approve or refuse. We also decide exemptions
from the zoning rules, we inspect what is actually built, we sign off
finished work, and we deal with building that was never applied for.
who_comes_to_us: >
Homeowners who want a garage, an extension or a new window, and who
have never read a regulation in their life. Architects and
engineering firms who file on behalf of owners; they have to be
approved by us before they may file anything. Neighbours who got a
notice in the post and do not agree with what is planned next door.
The other authorities we are obliged to ask: the road authority, the
fire service, the heritage office, the county. People who ring to say
something is going up behind their fence without permission. And
anyone who wants to sit down with us before they spend eighty
thousand on drawings.
what_we_keep_track_of: >
Pre-application meetings: someone asks for one, we find a time, we
meet, and we write down what we told them so they can hold us to it.
Applications: they arrive, someone checks whether the papers are all
there, and if something is missing we write and ask for it, and the
twelve-week clock stops until they answer. Often we have to ask
twice. When it is complete we send it out to the neighbours and to
the agencies and wait six weeks. Then a case officer writes a
recommendation, and the head of section signs the decision: approved,
approved with conditions, or refused. People can withdraw at any
point, and quite a few do once they hear from the neighbours.
Exemptions: if what someone wants breaks the zoning rules they can
ask for an exemption. It rides along with the application but it is a
decision of its own, and we are not allowed to grant one before the
county has been asked.
Objections: a neighbour who got a notice writes to us within the
hearing period. Each objection belongs to an application. We register
it, the applicant gets to answer it, and the case officer has to
address every single one in the decision, by name.
Hearing answers: we ask an agency, they answer, or they do not, and
when the deadline has passed we go on without them.
Appeals: for three weeks after a decision anyone with an interest can
appeal it. We go through it ourselves first, and if we change our own
mind that is the end of it. If we do not, it goes to the appeals
board, who meet once a month and either uphold us or overturn us.
Inspections: we pick cases and go and look, on site. Either it is as
approved, or we write up what is wrong and set a date for it to be
put right, and then we go back.
Finishing: when the work is done the firm asks for a completion
certificate. If they want to move in before everything is done they
can ask for a temporary permission instead. We check what was
inspected and what is still outstanding before we sign anything.
Illegal building: someone reports it, we go and look, we write to the
owner and they have to explain themselves, and then they either apply
for it properly, take it down, or we fine them weekly until they do.
Approved firms: a firm sends us their registration, their insurance
and what they are qualified for, we check it, and then they are on
the list and may file applications.
who_is_involved: >
The front desk logs what comes in over the counter and on the phone,
and keeps the archive. Four case officers carry the cases. The head
of section signs every decision and every exemption; a case officer
may not sign their own. Two inspectors are out on site most of the
week and write up what they find on a phone in a cold wind. The
appeals board is seven elected politicians who meet on the third
Tuesday of the month and read what we send them. The agencies are
outside the building altogether and only ever answer hearings. The
approved firms file applications and answer objections on behalf of
their clients.
what_slows_us_down: >
The twelve-week clock, and the fact that stopping it and starting it
again is done by hand in a spreadsheet. Applications that arrive
missing half the drawings. Objections that come in on paper and get
stapled to the wrong case. Neighbours ringing to ask what is
happening with the case behind their house, which we are obliged to
tell them and which takes ten minutes every time. Agencies that never
answer at all. And nobody outside this building can see a case
without asking us for it.
## Your last attempt was refused
need "exemption": a need that answers another is reached from that one's list, not a door or a group's page
Fix that and return the whole plan again.
```yaml
business: Vestmark kommune - Building and Planning
language: en
contact: { name: Solveig Hauge, email: byggesak@vestmark.example }
about: >
We are the building authority for a municipality of twenty-one
thousand people. Anyone who wants to build, demolish, divide a
property or change what a building is used for has to come to us
first. We check the drawings against the zoning map and the building
regulations, we let the neighbours and the other authorities have
their say, and then we approve or refuse. We also decide exemptions
from the zoning rules, we inspect what is actually built, we sign off
finished work, and we deal with building that was never applied for.
mail: { from: "Vestmark kommune Building and Planning <post@vestmark.example>", reply_to: byggesak@vestmark.example }
does:
- id: check-and-decide
for: application
text: >
We check your drawings against the zoning map and the building
regulations, let the neighbours and the other authorities have
their say, and then approve or refuse. You can follow your case
here the whole way.
- id: firms-file-here
for: firm-application
text: >
Approved firms file applications for their clients here, see what
is missing and ask for the completion certificate when the work is done.
doors:
- id: build
who: You want to build, demolish, divide a property or change what a building is used for
- id: neighbour
who: Something is planned or going up next door to you
- id: firm
who: You are an architect or an engineering firm filing on behalf of owners
invites_by: [head_of_section]
needs:
- id: pre-application-meeting
who: Anyone who wants to sit down with us before they spend money on drawings
wants: A meeting with a case officer, and a written note of what we told them
door: build
lands_in: pre_application_meetings
handled_by: case_officers
stages: [open, scheduled, met, written_up, cancelled]
done_when: [written_up, cancelled]
success: [written_up]
turned_down_from: [open, scheduled]
moves_by: { cancelled: [submitter, case_officers] }
watched_by: [front_desk]
mails: { open: submitter, scheduled: submitter, written_up: submitter, cancelled: submitter }
stages_text: { open: asked for, scheduled: time found, met: meeting held, written_up: written down and sent, cancelled: cancelled }
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: property_address }
- { name: what_you_plan, type: textarea }
- { name: phone, type: tel, optional: true }
- { name: place, type: location, optional: true }
- id: application
who: A homeowner who wants a garage, an extension, a new window or another change to their property
wants: Permission to build, demolish, divide a property or change what a building is used for
door: build
lands_in: applications
handled_by: case_officers
stages: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused, withdrawn]
done_when: [approved, approved_with_conditions, refused, withdrawn]
success: [approved, approved_with_conditions]
skippable: [papers_missing, papers_received]
reached_from:
papers_missing: [open, papers_received, complete, in_hearing]
refused: [recommended]
moves_by:
papers_received: [submitter]
approved: [head_of_section]
approved_with_conditions: [head_of_section]
refused: [head_of_section]
withdrawn: [submitter, case_officers]
watched_by: [public, front_desk, inspectors]
public_states: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused]
mails:
open: submitter
papers_missing: submitter
complete: submitter
in_hearing: submitter
approved: submitter
approved_with_conditions: submitter
refused: submitter
withdrawn: submitter
deadlines: { in_hearing: { days: 42, to: hearing_over } }
stages_text:
open: received
papers_missing: papers missing, clock stopped
papers_received: missing papers sent in
complete: complete, clock running
in_hearing: out to neighbours and agencies
hearing_over: hearing over
recommended: recommendation written
approved: approved
approved_with_conditions: approved with conditions
refused: refused
withdrawn: withdrawn
max_fields: 5
collects:
- { name: name, private: true }
- { name: email, type: email, private: true }
- { name: property_address }
- { name: kind_of_work, type: select, options: [New building, Extension, Garage or outbuilding, Window or facade change, Demolition, Dividing a property, Change of use] }
- { name: what_you_want_to_do, type: textarea }
- { name: enclosed, type: select, multiple: true, optional: true, options: [Site plan, Floor plans, Elevations, Section drawing, Neighbour notices sent, Statement from the owner] }
- { name: phone, type: tel, optional: true, private: true }
- { name: place, type: location, optional: true }
- id: firm-application
who: An approved architect or engineering firm filing on behalf of an owner
wants: To file a building application for a client and see what is missing
door: firm
enters_as: approved_firms
requires: Your firm must be on our list of approved firms before it may file anything.
lands_in: applications
handled_by: case_officers
stages: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused, withdrawn]
done_when: [approved, approved_with_conditions, refused, withdrawn]
success: [approved, approved_with_conditions]
skippable: [papers_missing, papers_received]
reached_from:
papers_missing: [open, papers_received, complete, in_hearing]
refused: [recommended]
moves_by:
papers_received: [submitter]
approved: [head_of_section]
approved_with_conditions: [head_of_section]
refused: [head_of_section]
withdrawn: [submitter, case_officers]
watched_by: [public, front_desk, inspectors]
public_states: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused]
mails:
open: submitter
papers_missing: submitter
complete: submitter
in_hearing: submitter
approved: submitter
approved_with_conditions: submitter
refused: submitter
withdrawn: submitter
deadlines: { in_hearing: { days: 42, to: hearing_over } }
stages_text:
open: received
papers_missing: papers missing, clock stopped
papers_received: missing papers sent in
complete: complete, clock running
in_hearing: out to neighbours and agencies
hearing_over: hearing over
recommended: recommendation written
approved: approved
approved_with_conditions: approved with conditions
refused: refused
withdrawn: withdrawn
max_fields: 6
collects:
- { name: name, private: true }
- { name: email, type: email, private: true }
- { name: property_address }
- { name: kind_of_work, type: select, options: [New building, Extension, Garage or outbuilding, Window or facade change, Demolition, Dividing a property, Change of use] }
- { name: what_you_want_to_do, type: textarea }
- { name: enclosed, type: select, multiple: true, options: [Site plan, Floor plans, Elevations, Section drawing, Neighbour notices sent, Statement from the owner] }
- { name: owner_name, optional: true, private: true }
- { name: phone, type: tel, optional: true, private: true }
- { name: place, type: location, optional: true }
- id: exemption
who: An applicant whose plans break the zoning rules
wants: An exemption from the zoning rules, decided alongside their application
door: build
about: application
requires: An application with us; the exemption rides along with it and is asked for from its row on the list of cases.
lands_in: exemptions
handled_by: case_officers
stages: [open, county_asked, county_heard, granted, refused]
done_when: [granted, refused]
success: [granted]
moves_by: { granted: [head_of_section], refused: [head_of_section] }
watched_by: [front_desk]
mails: { open: submitter, county_asked: submitter, granted: submitter, refused: submitter }
deadlines: { county_asked: { days: 42, to: county_heard } }
stages_text: { open: received, county_asked: county asked, county_heard: county has answered or its deadline has passed, granted: granted, refused: refused }
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: rule_it_breaks }
- { name: why_it_should_be_allowed, type: textarea }
- id: objection
who: A neighbour who got a notice in the post and does not agree with what is planned next door
wants: To object to an application and have the objection answered in the decision
door: neighbour
about: application
requires: The application must still be out for hearing; objections are taken until the six weeks are up.
lands_in: objections
handled_by: case_officers
stages: [open, registered, answered, addressed]
done_when: [addressed]
success: [addressed]
skippable: [answered]
moves_by: { registered: [front_desk, case_officers], answered: [approved_firms, case_officers] }
watched_by: [front_desk, head_of_section]
mails: { open: submitter, registered: owner, addressed: submitter }
stages_text: { open: received, registered: registered on the case, answered: answered by the applicant, addressed: addressed in the decision }
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: your_property }
- { name: objection, type: textarea }
- { name: phone, type: tel, optional: true }
- id: logged-objection
who: The front desk, when an objection comes in on paper or over the counter
wants: To put the objection on the right case straight away
enters_as: front_desk
about: application
lands_in: objections
handled_by: case_officers
stages: [open, registered, answered, addressed]
done_when: [addressed]
success: [addressed]
skippable: [answered]
moves_by: { registered: [front_desk, case_officers], answered: [approved_firms, case_officers] }
watched_by: [front_desk, head_of_section]
mails: { registered: owner }
stages_text: { open: received, registered: registered on the case, answered: answered by the applicant, addressed: addressed in the decision }
max_fields: 4
collects:
- { name: name }
- { name: your_property }
- { name: objection, type: textarea }
- { name: received_on, type: date }
- { name: phone, type: tel, optional: true }
- id: hearing-request
who: A case officer who is obliged to ask another authority about an application
wants: To ask the road authority, the fire service, the heritage office or the county, and go on when the deadline has passed
enters_as: case_officers
about: application
lands_in: hearing_answers
handled_by: case_officers
stages: [open, answered, no_answer]
done_when: [answered, no_answer]
success: [answered]
moves_by: { answered: [agencies, case_officers] }
watched_by: [agencies, front_desk]
deadlines: { open: { days: 42, to: no_answer } }
stages_text: { open: asked, answered: answered, no_answer: deadline passed without an answer }
max_fields: 3
collects:
- { name: agency, type: select, options: [Road authority, Fire service, Heritage office, County] }
- { name: what_we_ask, type: textarea }
- { name: answer_by, type: date }
- id: appeal
who: Anyone with an interest in a decision, the applicant or a neighbour
wants: To appeal a decision we have made
about: application
requires: A decision on the application, made no more than three weeks ago.
lands_in: appeals
handled_by: case_officers
stages: [open, under_review, decision_changed, sent_to_board, upheld, overturned, dismissed]
done_when: [decision_changed, upheld, overturned, dismissed]
success: [decision_changed, upheld, overturned]
turned_down_from: [open, under_review]
reached_from: { decision_changed: [under_review] }
moves_by: { decision_changed: [head_of_section], upheld: [appeals_board], overturned: [appeals_board] }
watched_by: [appeals_board, head_of_section, front_desk]
mails: { open: submitter, decision_changed: submitter, sent_to_board: submitter, upheld: submitter, overturned: submitter, dismissed: submitter }
stages_text: { open: received, under_review: we are going through it ourselves, decision_changed: we changed our own decision, sent_to_board: sent to the appeals board, upheld: decision upheld by the board, overturned: decision overturned by the board, dismissed: dismissed }
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: your_interest, type: select, options: [I am the applicant, I am a neighbour, Other] }
- { name: grounds, type: textarea }
- { name: phone, type: tel, optional: true }
- id: illegal-building-report
who: Someone who sees something going up behind their fence without permission
wants: To tell us, so that we go and look
door: neighbour
lands_in: illegal_building
handled_by: case_officers
stages: [open, inspected, owner_written_to, explained, fined, applied_for, taken_down, nothing_illegal]
done_when: [applied_for, taken_down, nothing_illegal]
success: [applied_for, taken_down]
skippable: [fined]
turned_down_from: [open, inspected, explained]
moves_by: { inspected: [inspectors], fined: [head_of_section] }
watched_by: [front_desk, inspectors]
stages_text: { open: reported, inspected: we have been and looked, owner_written_to: owner written to, explained: owner has explained, fined: weekly fine running, applied_for: applied for properly, taken_down: taken down, nothing_illegal: nothing illegal found }
max_fields: 3
collects:
- { name: where }
- { name: what_is_being_built, type: textarea }
- { name: place, type: location, optional: true }
- { name: name, optional: true, private: true }
- { name: phone, type: tel, optional: true, private: true }
- id: logged-report
who: The front desk, when someone rings or comes in about building without permission
wants: To log the report so an inspector goes and looks
enters_as: front_desk
lands_in: illegal_building
handled_by: case_officers
stages: [open, inspected, owner_written_to, explained, fined, applied_for, taken_down, nothing_illegal]
done_when: [applied_for, taken_down, nothing_illegal]
success: [applied_for, taken_down]
skippable: [fined]
turned_down_from: [open, inspected, explained]
moves_by: { inspected: [inspectors], fined: [head_of_section] }
watched_by: [front_desk, inspectors]
stages_text: { open: reported, inspected: we have been and looked, owner_written_to: owner written to, explained: owner has explained, fined: weekly fine running, applied_for: applied for properly, taken_down: taken down, nothing_illegal: nothing illegal found }
max_fields: 3
collects:
- { name: where }
- { name: what_is_being_built, type: textarea }
- { name: place, type: location, optional: true }
- { name: name, optional: true, private: true }
- { name: phone, type: tel, optional: true, private: true }
- id: inspection
who: An inspector on site, writing on a phone in a cold wind
wants: To write up what was found on a case and set a date for what must be put right
enters_as: inspectors
about: application
lands_in: inspections
handled_by: inspectors
stages: [open, to_put_right, as_approved]
done_when: [as_approved]
success: [as_approved]
skippable: [to_put_right]
watched_by: [case_officers, head_of_section]
stages_text: { open: inspected, to_put_right: to be put right, then we go back, as_approved: as approved }
max_fields: 2
collects:
- { name: finding, type: select, options: [As approved, Something is wrong] }
- { name: what_is_wrong, type: textarea, optional: true }
- { name: put_right_by, type: date, optional: true }
- { name: place, type: location, optional: true }
- id: completion-certificate
who: An approved firm whose work on a case is done
wants: A completion certificate for the finished work
door: firm
enters_as: approved_firms
about: application
requires: Your firm must be on our list of approved firms, and the application must be approved.
lands_in: completion_certificates
handled_by: case_officers
stages: [open, checked, issued, refused]
done_when: [issued, refused]
success: [issued]
moves_by: { issued: [head_of_section], refused: [head_of_section] }
watched_by: [inspectors, front_desk]
mails: { open: submitter, issued: submitter, refused: submitter }
stages_text: { open: asked for, checked: inspections and outstanding work checked, issued: certificate signed, refused: refused }
max_fields: 5
collects:
- { name: name }
- { name: email, type: email }
- { name: finished_on, type: date }
- { name: what_was_built, type: textarea }
- { name: still_outstanding, type: textarea, optional: true }
- id: temporary-permission
who: An approved firm whose client wants to move in before everything is done
wants: A temporary permission to use the building
door: firm
enters_as: approved_firms
about: application
requires: Your firm must be on our list of approved firms, and the application must be approved.
lands_in: temporary_permissions
handled_by: case_officers
stages: [open, checked, issued, refused]
done_when: [issued, refused]
success: [issued]
moves_by: { issued: [head_of_section], refused: [head_of_section] }
watched_by: [inspectors, front_desk]
mails: { open: submitter, issued: submitter, refused: submitter }
stages_text: { open: asked for, checked: inspections and outstanding work checked, issued: temporary permission signed, refused: refused }
max_fields: 6
collects:
- { name: name }
- { name: email, type: email }
- { name: move_in_on, type: date }
- { name: still_outstanding, type: textarea }
- { name: finished_by, type: date }
- id: firm-approval
who: An architect or engineering firm that wants to file applications for owners
wants: To be approved by us and put on the list of firms that may file
door: firm
lands_in: approved_firm_requests
handled_by: case_officers
stages: [open, checked, listed, refused]
done_when: [listed, refused]
success: [listed]
moves_by: { listed: [head_of_section], refused: [head_of_section] }
watched_by: [public, front_desk]
public_states: [listed]
mails: { open: submitter, listed: submitter, refused: submitter }
grants: { listed: approved_firms }
stages_text: { open: received, checked: registration, insurance and qualifications checked, listed: on the list, refused: refused }
max_fields: 6
collects:
- { name: firm }
- { name: name, private: true }
- { name: email, type: email, private: true }
- { name: registration_number }
- { name: insurance, private: true }
- { name: qualified_for, type: select, multiple: true, options: [Applying on behalf of owners, Architectural design, Structural engineering, Fire safety design, Geotechnical engineering, Carrying out the work, Independent control] }
- { name: phone, type: tel, optional: true, private: true }
```
Reply with the YAML only, no prose, no code fences.
@@ -0,0 +1,418 @@
business: Vestmark kommune - Building and Planning
language: en
contact: { name: Solveig Hauge, email: byggesak@vestmark.example }
about: >
We are the building authority for a municipality of twenty-one
thousand people. Anyone who wants to build, demolish, divide a
property or change what a building is used for has to come to us
first. We check the drawings against the zoning map and the building
regulations, we let the neighbours and the other authorities have
their say, and then we approve or refuse. We also decide exemptions
from the zoning rules, we inspect what is actually built, we sign off
finished work, and we deal with building that was never applied for.
mail: { from: "Vestmark kommune Building and Planning <post@vestmark.example>", reply_to: byggesak@vestmark.example }
does:
- id: check-and-decide
for: application
text: >
We check your drawings against the zoning map and the building
regulations, let the neighbours and the other authorities have
their say, and then approve or refuse. Every case is on the list
here, so you and your neighbours can follow it the whole way,
and object to it or appeal it from its own row.
- id: firms-file-here
for: firm-application
text: >
Approved firms file applications for their clients here, see what
is missing and ask for the completion certificate when the work is done.
doors:
- id: build
who: You want to build, demolish, divide a property or change what a building is used for
- id: firm
who: You are an architect or an engineering firm filing on behalf of owners
invites_by: [head_of_section]
needs:
- id: pre-application-meeting
who: Anyone who wants to sit down with us before they spend money on drawings
wants: A meeting with a case officer, and a written note of what we told them
door: build
lands_in: pre_application_meetings
handled_by: case_officers
stages: [open, scheduled, met, written_up, cancelled]
done_when: [written_up, cancelled]
success: [written_up]
turned_down_from: [open, scheduled]
moves_by: { cancelled: [submitter, case_officers] }
watched_by: [front_desk]
mails: { open: submitter, scheduled: submitter, written_up: submitter, cancelled: submitter }
stages_text: { open: asked for, scheduled: time found, met: meeting held, written_up: written down and sent, cancelled: cancelled }
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: property_address }
- { name: what_you_plan, type: textarea }
- { name: phone, type: tel, optional: true }
- { name: place, type: location, optional: true }
- id: application
who: A homeowner who wants a garage, an extension, a new window or another change to their property
wants: Permission to build, demolish, divide a property or change what a building is used for
door: build
lands_in: applications
handled_by: case_officers
stages: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused, withdrawn]
done_when: [approved, approved_with_conditions, refused, withdrawn]
success: [approved, approved_with_conditions]
skippable: [papers_missing, papers_received]
reached_from:
papers_missing: [open, papers_received, complete, in_hearing]
refused: [recommended]
moves_by:
papers_received: [submitter]
approved: [head_of_section]
approved_with_conditions: [head_of_section]
refused: [head_of_section]
withdrawn: [submitter, case_officers]
watched_by: [public, front_desk, inspectors]
public_states: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused]
mails:
open: submitter
papers_missing: submitter
complete: submitter
in_hearing: submitter
approved: submitter
approved_with_conditions: submitter
refused: submitter
withdrawn: submitter
deadlines: { in_hearing: { days: 42, to: hearing_over } }
stages_text:
open: received
papers_missing: papers missing, clock stopped
papers_received: missing papers sent in
complete: complete, clock running
in_hearing: out to neighbours and agencies
hearing_over: hearing over
recommended: recommendation written
approved: approved
approved_with_conditions: approved with conditions
refused: refused
withdrawn: withdrawn
max_fields: 5
collects:
- { name: name, private: true }
- { name: email, type: email, private: true }
- { name: property_address }
- { name: kind_of_work, type: select, options: [New building, Extension, Garage or outbuilding, Window or facade change, Demolition, Dividing a property, Change of use] }
- { name: what_you_want_to_do, type: textarea }
- { name: enclosed, type: select, multiple: true, optional: true, options: [Site plan, Floor plans, Elevations, Section drawing, Neighbour notices sent, Statement from the owner] }
- { name: phone, type: tel, optional: true, private: true }
- { name: place, type: location, optional: true }
- id: firm-application
who: An approved architect or engineering firm filing on behalf of an owner
wants: To file a building application for a client and see what is missing
door: firm
enters_as: approved_firms
requires: Your firm must be on our list of approved firms before it may file anything.
lands_in: applications
handled_by: case_officers
stages: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused, withdrawn]
done_when: [approved, approved_with_conditions, refused, withdrawn]
success: [approved, approved_with_conditions]
skippable: [papers_missing, papers_received]
reached_from:
papers_missing: [open, papers_received, complete, in_hearing]
refused: [recommended]
moves_by:
papers_received: [submitter]
approved: [head_of_section]
approved_with_conditions: [head_of_section]
refused: [head_of_section]
withdrawn: [submitter, case_officers]
watched_by: [public, front_desk, inspectors]
public_states: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused]
mails:
open: submitter
papers_missing: submitter
complete: submitter
in_hearing: submitter
approved: submitter
approved_with_conditions: submitter
refused: submitter
withdrawn: submitter
deadlines: { in_hearing: { days: 42, to: hearing_over } }
stages_text:
open: received
papers_missing: papers missing, clock stopped
papers_received: missing papers sent in
complete: complete, clock running
in_hearing: out to neighbours and agencies
hearing_over: hearing over
recommended: recommendation written
approved: approved
approved_with_conditions: approved with conditions
refused: refused
withdrawn: withdrawn
max_fields: 6
collects:
- { name: name, private: true }
- { name: email, type: email, private: true }
- { name: property_address }
- { name: kind_of_work, type: select, options: [New building, Extension, Garage or outbuilding, Window or facade change, Demolition, Dividing a property, Change of use] }
- { name: what_you_want_to_do, type: textarea }
- { name: enclosed, type: select, multiple: true, options: [Site plan, Floor plans, Elevations, Section drawing, Neighbour notices sent, Statement from the owner] }
- { name: owner_name, optional: true, private: true }
- { name: phone, type: tel, optional: true, private: true }
- { name: place, type: location, optional: true }
- id: exemption
who: An applicant whose plans break the zoning rules
wants: An exemption from the zoning rules, decided alongside their application
about: application
requires: An application with us; the exemption rides along with it and is asked for from its row on the list of cases.
lands_in: exemptions
handled_by: case_officers
stages: [open, county_asked, county_heard, granted, refused]
done_when: [granted, refused]
success: [granted]
moves_by: { granted: [head_of_section], refused: [head_of_section] }
watched_by: [front_desk]
mails: { open: submitter, county_asked: submitter, granted: submitter, refused: submitter }
deadlines: { county_asked: { days: 42, to: county_heard } }
stages_text: { open: received, county_asked: county asked, county_heard: county has answered or its deadline has passed, granted: granted, refused: refused }
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: rule_it_breaks }
- { name: why_it_should_be_allowed, type: textarea }
- id: objection
who: A neighbour who got a notice in the post and does not agree with what is planned next door
wants: To object to an application and have the objection answered in the decision
about: application
requires: The application must still be out for hearing; objections are taken until the six weeks are up.
lands_in: objections
handled_by: case_officers
stages: [open, registered, answered, addressed]
done_when: [addressed]
success: [addressed]
skippable: [answered]
moves_by: { registered: [front_desk, case_officers], answered: [approved_firms, case_officers] }
watched_by: [front_desk, head_of_section]
mails: { open: submitter, registered: owner, addressed: submitter }
stages_text: { open: received, registered: registered on the case, answered: answered by the applicant, addressed: addressed in the decision }
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: your_property }
- { name: objection, type: textarea }
- { name: phone, type: tel, optional: true }
- id: logged-objection
who: The front desk, when an objection comes in on paper or over the counter
wants: To put the objection on the right case straight away, instead of stapling it to a folder
enters_as: front_desk
lands_in: paper_objections
handled_by: case_officers
stages: [open, registered, answered, addressed]
done_when: [addressed]
success: [addressed]
skippable: [answered]
moves_by: { registered: [front_desk, case_officers], answered: [approved_firms, case_officers] }
watched_by: [front_desk, head_of_section]
stages_text: { open: received, registered: registered on the case, answered: answered by the applicant, addressed: addressed in the decision }
max_fields: 5
collects:
- { name: application_reference }
- { name: name }
- { name: objection, type: textarea }
- { name: received_on, type: date }
- { name: your_property, optional: true }
- { name: phone, type: tel, optional: true }
- id: hearing-request
who: A case officer who is obliged to ask another authority about an application
wants: To ask the road authority, the fire service, the heritage office or the county, and go on when the deadline has passed
enters_as: case_officers
lands_in: hearing_answers
handled_by: case_officers
stages: [open, answered, no_answer]
done_when: [answered, no_answer]
success: [answered]
moves_by: { answered: [agencies, case_officers] }
watched_by: [agencies, front_desk]
deadlines: { open: { days: 42, to: no_answer } }
stages_text: { open: asked, answered: answered, no_answer: deadline passed without an answer }
max_fields: 4
collects:
- { name: application_reference }
- { name: agency, type: select, options: [Road authority, Fire service, Heritage office, County] }
- { name: what_we_ask, type: textarea }
- { name: answer_by, type: date, optional: true }
- id: appeal
who: Anyone with an interest in a decision, the applicant or a neighbour
wants: To appeal a decision we have made
about: application
requires: A decision on the application, made no more than three weeks ago.
lands_in: appeals
handled_by: case_officers
stages: [open, under_review, decision_changed, sent_to_board, upheld, overturned, dismissed]
done_when: [decision_changed, upheld, overturned, dismissed]
success: [decision_changed, upheld, overturned]
turned_down_from: [open, under_review]
reached_from: { decision_changed: [under_review] }
moves_by: { decision_changed: [head_of_section], upheld: [appeals_board], overturned: [appeals_board] }
watched_by: [appeals_board, head_of_section, front_desk]
mails: { open: submitter, decision_changed: submitter, sent_to_board: submitter, upheld: submitter, overturned: submitter, dismissed: submitter }
stages_text: { open: received, under_review: we are going through it ourselves, decision_changed: we changed our own decision, sent_to_board: sent to the appeals board, upheld: decision upheld by the board, overturned: decision overturned by the board, dismissed: dismissed }
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: your_interest, type: select, options: [I am the applicant, I am a neighbour, Other] }
- { name: grounds, type: textarea }
- { name: phone, type: tel, optional: true }
- id: illegal-building-report
who: Someone who sees something going up behind their fence without permission
wants: To tell us, so that we go and look
lands_in: illegal_building
handled_by: case_officers
stages: [open, inspected, owner_written_to, explained, fined, applied_for, taken_down, nothing_illegal]
done_when: [applied_for, taken_down, nothing_illegal]
success: [applied_for, taken_down]
skippable: [fined]
turned_down_from: [open, inspected, explained]
moves_by: { inspected: [inspectors], fined: [head_of_section] }
watched_by: [front_desk, inspectors]
stages_text: { open: reported, inspected: we have been and looked, owner_written_to: owner written to, explained: owner has explained, fined: weekly fine running, applied_for: applied for properly, taken_down: taken down, nothing_illegal: nothing illegal found }
max_fields: 3
collects:
- { name: where }
- { name: what_is_being_built, type: textarea }
- { name: place, type: location, optional: true }
- { name: name, optional: true, private: true }
- { name: phone, type: tel, optional: true, private: true }
- id: logged-report
who: The front desk, when someone rings or comes in about building without permission
wants: To log the report so an inspector goes and looks
enters_as: front_desk
lands_in: illegal_building
handled_by: case_officers
stages: [open, inspected, owner_written_to, explained, fined, applied_for, taken_down, nothing_illegal]
done_when: [applied_for, taken_down, nothing_illegal]
success: [applied_for, taken_down]
skippable: [fined]
turned_down_from: [open, inspected, explained]
moves_by: { inspected: [inspectors], fined: [head_of_section] }
watched_by: [front_desk, inspectors]
stages_text: { open: reported, inspected: we have been and looked, owner_written_to: owner written to, explained: owner has explained, fined: weekly fine running, applied_for: applied for properly, taken_down: taken down, nothing_illegal: nothing illegal found }
max_fields: 3
collects:
- { name: where }
- { name: what_is_being_built, type: textarea }
- { name: place, type: location, optional: true }
- { name: name, optional: true, private: true }
- { name: phone, type: tel, optional: true, private: true }
- id: inspection
who: An inspector on site, writing on a phone in a cold wind
wants: To write up what was found on a case and set a date for what must be put right
enters_as: inspectors
lands_in: inspections
handled_by: inspectors
stages: [open, to_put_right, as_approved]
done_when: [as_approved]
success: [as_approved]
skippable: [to_put_right]
watched_by: [case_officers, head_of_section]
stages_text: { open: inspected, to_put_right: to be put right, then we go back, as_approved: as approved }
max_fields: 3
collects:
- { name: application_reference }
- { name: finding, type: select, options: [As approved, Something is wrong] }
- { name: what_is_wrong, type: textarea, optional: true }
- { name: put_right_by, type: date, optional: true }
- { name: place, type: location, optional: true }
- id: completion-certificate
who: An approved firm whose work on a case is done
wants: A completion certificate for the finished work
door: firm
enters_as: approved_firms
requires: Your firm must be on our list of approved firms, and the application must be approved; have its reference ready.
lands_in: completion_certificates
handled_by: case_officers
stages: [open, checked, issued, refused]
done_when: [issued, refused]
success: [issued]
moves_by: { issued: [head_of_section], refused: [head_of_section] }
watched_by: [inspectors, front_desk]
mails: { open: submitter, issued: submitter, refused: submitter }
stages_text: { open: asked for, checked: inspections and outstanding work checked, issued: certificate signed, refused: refused }
max_fields: 5
collects:
- { name: name }
- { name: email, type: email }
- { name: application_reference }
- { name: finished_on, type: date }
- { name: what_was_built, type: textarea, optional: true }
- { name: still_outstanding, type: textarea, optional: true }
- id: temporary-permission
who: An approved firm whose client wants to move in before everything is done
wants: A temporary permission to use the building
door: firm
enters_as: approved_firms
requires: Your firm must be on our list of approved firms, and the application must be approved; have its reference ready.
lands_in: temporary_permissions
handled_by: case_officers
stages: [open, checked, issued, refused]
done_when: [issued, refused]
success: [issued]
moves_by: { issued: [head_of_section], refused: [head_of_section] }
watched_by: [inspectors, front_desk]
mails: { open: submitter, issued: submitter, refused: submitter }
stages_text: { open: asked for, checked: inspections and outstanding work checked, issued: temporary permission signed, refused: refused }
max_fields: 6
collects:
- { name: name }
- { name: email, type: email }
- { name: application_reference }
- { name: move_in_on, type: date }
- { name: still_outstanding, type: textarea }
- { name: finished_by, type: date, optional: true }
- id: firm-approval
who: An architect or engineering firm that wants to file applications for owners
wants: To be approved by us and put on the list of firms that may file
door: firm
lands_in: approved_firm_requests
handled_by: case_officers
stages: [open, checked, listed, refused]
done_when: [listed, refused]
success: [listed]
moves_by: { listed: [head_of_section], refused: [head_of_section] }
watched_by: [public, front_desk]
public_states: [listed]
mails: { open: submitter, listed: submitter, refused: submitter }
grants: { listed: approved_firms }
stages_text: { open: received, checked: registration, insurance and qualifications checked, listed: on the list, refused: refused }
max_fields: 6
collects:
- { name: firm }
- { name: name, private: true }
- { name: email, type: email, private: true }
- { name: registration_number }
- { name: insurance, private: true }
- { name: qualified_for, type: select, multiple: true, options: [Applying on behalf of owners, Architectural design, Structural engineering, Fire safety design, Geotechnical engineering, Carrying out the work, Independent control] }
- { name: phone, type: tel, optional: true, private: true }
@@ -0,0 +1,716 @@
# plan.yaml
A plan is a needs spec that also says what each form collects. A
builder turns it into a working site with no further decisions, so
every structural fact about the business has to be in it.
```yaml
business: <name>
language: en # the intake's language code
contact: { name: <who answers for the site>, email: <their email> }
about: >
What the business does, in its own words.
mail: { from: "<name> <post@their-domain>", reply_to: <their inbox> }
# who every mail the site sends comes from; required as soon
# as any need has `mails`
does: # the front door's first card: what the business does, one
- id: kebab-case # or two features, one role each, no button. Say it for the
for: <need id> # role the business exists for and the next one it serves.
text: what it does for them, in the intake's own words
shows: # what the site shows as it is: a live figure, the latest
- id: kebab-case # releases, what has been built; `resource` is portal's block
text: one line on what it is
resource: { public: true, source: { kind: url, url: https://... } }
doors: # a first question before the forms, only when the offers
- id: kebab-case # are more than one page holds (measured: four doors beat
who: who comes through it # ten offers on one page; six offers on one page beat doors)
groups: # groups with a label the public may see: the committees
- { id: traffic, label: Traffic, invited_by: [board] } # a person can ask to join (optional; label defaults to the id)
invites_by: [board] # groups whose desk may invite people into every desk
needs:
- id: kebab-case # ASCII only
who: the kind of person, in plain words, in the intake's language
wants: what they want from the business
door: <door id> # the door this public need sits behind; omit to put it on the front door
enters_as: <group> # ONLY for a role inside the business; omit for the public
lands_in: <bucket> # snake_case, ASCII
handled_by: <group> # the role that must see and move the record
stages: [open, <stage>, ..., <end>, <end>]
# EVERY stage the business said a case goes through, first to
# last, read off their own sentences one verb at a time: "they
# come in, we go and look, we send a quote, we win or lose it"
# is [open, surveyed, quoted, won, lost]. A pipeline is not an
# inbox: "answered" is rarely the real outcome.
done_when: [<end>, <end>] # every stage that counts as finished, good or bad
success: [<end>] # the finished stages that are a good outcome for the business
skippable: [<stage>] # stages a case may pass over (papers already complete)
requires: <one sentence> # what the person must ALREADY have or be for this to work:
# a membership, a reference number, the link from a mail, an
# account. Stated on the card above the form. Omit when there
# is none; never invent one
turned_down_from: [open, <stage>]
# the unfinished stages a case can still be turned down from;
# omit for every one. An applicant is declined before they
# start, not after - after, they depart
reached_from: { <stage>: [<stage>, ...] }
# where a stage is entered from, when the line does not say it.
# Two things need it and nothing else does: a case SENT BACK to
# a stage it was already past ("papers missing" again, after the
# hearing turned something up), and a GOOD ENDING partway along,
# where a case finishes well without walking to the end ("we
# changed our own decision", instead of passing it upwards).
# A stage named here is entered from exactly those stages and
# nowhere else, so it also says where a refusal may NOT come
# from. Omit unless the business described one of those two
moves_by: { <stage>: [<group>, ...] }
# only where someone other than handled_by moves a case INTO a
# stage: another group, or `submitter` (the person who sent the
# form; the form must then collect a required `email`)
watched_by: [<group>] # groups that see these cases and move nothing; `public` opens a
# read-only page of the bucket to everyone (contact details hidden)
mails: { open: submitter, <end>: submitter, <stage>: <address> }
# who hears when a case enters a stage: `submitter` (the form
# must then collect a required `email`) or one address. Tell the
# person on arrival and on every decision that is about them.
grants: { <stage>: <group> }
# a stage that makes the person a member of a group when their
# case arrives (an approval that IS membership); the form must
# then collect a required `name` and a required `email`
deadlines: { <stage>: { days: 30, to: <stage> } }
# a stage a clock moves on from when a case sits in it that long
# (a notice that expires, a hearing with no answer); only along
# a move the stages already allow
public_states: [<stage>] # with `public` in watched_by: the stages the public list shows
# (a noticeboard shows what is up, not what was taken down)
stages_text: { open: <words>, <stage>: <words> }
# each stage in the intake's language, where the ASCII id
# would read wrong to a person: "ikke_lost" is "ikke løst"
events: { open: applied } # ONLY when rebuilding a live site: the event names its
# aggregates.yaml already has, so its records keep replaying
attended_by: > # ONLY for a stage no desk button moves: the automation that does
what moves it, in a sentence
max_fields: 4 # decide this BEFORE writing collects, from what the intake
# says about the person; a budget that equals the form's size
# is counted, not decided, and is reported as such
# how many required fields THIS person will tolerate, from what
# the intake says about them: someone on a phone with gloves
# on gets 3, a first enquiry 4 to 6, a firm's paperwork 5 to 6
collects: # the form; name is snake_case ASCII, type one of
# text (default), email, tel, textarea, date, select, location
# (a pin on a map, stored as lat/lon/zoom; optional: true,
# since a map needs a browser that can draw one)
- { name: name }
- { name: phone, type: tel }
- { name: problem, type: textarea }
- { name: urgency, type: select, options: [This week, This month, No rush] }
- { name: can_do, type: select, multiple: true, options: [Drive, Cook, Carry] } # any number
- { name: committee, type: select, options_from: groups } # the labelled groups above
- { name: address, optional: true, private: true } # never on a public page
```
What a portal site can do - use what serves this business, leave the
rest. Each is one line in the plan, and the builder does the wiring:
- **Show, not only ask.** A bucket with `watched_by: [public]` becomes
a public list: its newest few records sit inline on the front door,
linked to the whole list, contact details pruned. What neighbours
reported and where it stands, which changes were approved, what is
on the noticeboard: a visitor who sees the place working trusts it,
and a person who reported something sees it being dealt with.
`public_states` shows only the stages worth showing.
- **Stay in dialogue.** `mails` tells the person at the stages that
are about them, and a reply to that mail comes back to the case as
a note. `moves_by: { <stage>: [submitter] }` gives them a move of
their own through their link: confirm, withdraw, say it is solved.
- **Let a decision do the work.** `grants` makes an approval into
membership: the person gets an account and a place in the group the
moment the case gets there; `deadlines` lets a stage end on its own
(a notice that expires, a request nobody took up); `invites_by` lets
a desk bring a person in without anyone touching an admin tool.
- **Let one record answer another.** A need `about` another need is
one answer per record of it, from that record's own row on the
public list: a neighbour saying "I can lend you that" to a notice, a
bid to a request. `mails: { open: owner }` sends the answer straight
to whoever posted the record, and the site keeps no queue - the
poster's inbox is the queue. The site never becomes a go-between.
- **Keep some things for members.** A need with `door` and `enters_as`
is offered to everyone on the door and taken on the group's page
behind sign-in, with name and address filled from the account: a
seat on a committee for members, a discount for customers. The
group is one a decision `grants`, so nobody has to be waved in.
- **Answer for the pages as a group.** `contact: { name, email, group }`
makes the contact a group's inbox rather than a person: no account
is made for it, and every member of the group may suggest changes
to the pages from the page itself.
- **Make the choices real.** `groups` with labels, and a select with
`options_from: groups`, so a form offers exactly the committees or
teams that exist; `multiple: true` where a person can pick several.
- **Place things.** A `location` field puts a pin on a map (where the
hazard is, where the job is), when the site has maps.
- **Open with the business itself.** `does` says what it does for the
roles it exists for; `shows` puts its live content beside that.
Rules:
- One need per (kind of person, thing they want). Work inside the
business counts: a role recording or posting something is a need
with `enters_as`. The intake's "what slows us down" usually names one.
- Groups are the roles the intake names, as snake_case identifiers.
- The front door opens with `does` (at most two features, one role
each) and `shows`, then holds at most seven offers: doors plus needs
with no door. A door with no need behind it is refused; a door on a
need with `enters_as` is the way to the members' page. A role `does`
speaks for must have a move
of its own after sending (`moves_by` with `submitter`) or a public
view, or it is a spectator.
- Every need whose form collects an email should tell the person on
arrival and on the decisions about them (`mails`); the plan then
needs `mail: { from }`.
- Every feature on a card explains itself: a list says what one row is
and what its buttons do, a form says what to have ready. If an
alternative only works for someone who already has something, say so
in `requires` - a condition the reader meets only after filling the
form in has already cost them the filling in.
- Needs that land in the same bucket must have the same stages,
done_when, skippable, moves_by, watched_by and handled_by.
- Every required field is one the business will use to act on the
record. If the intake gives no reason to need it, make it optional or
leave it out. The required fields must not exceed max_fields.
- Only `select` lists `options`, and it must list them.
- Everything a person reads (who, wants, about, select options) is in
the intake's language. Everything a machine reads (ids, buckets,
groups, stages, field names) is plain ASCII: no æ, ø, å.
- Write no personas.
# Task
A business filled in this intake. Write its plan.yaml: every need the intake implies, for the public and for each role inside the business, with the stages read off how the business says things progress, the form each need collects, and how much each person will tolerate.
## Intake
# A building authority's intake: the hardest sector the trainer has
# been given. Cases that pause and resume, cases that belong to other
# cases, a decision two roles sign, a deadline nobody in the building
# controls, and an appeal that reopens something already finished.
# Written the way the department head would write it, in plain words.
business: Vestmark kommune - Building and Planning
contact: { name: Solveig Hauge, email: byggesak@vestmark.example }
language: en
what_we_do: >
We are the building authority for a municipality of twenty-one
thousand people. Anyone who wants to build, demolish, divide a
property or change what a building is used for has to come to us
first. We check the drawings against the zoning map and the building
regulations, we let the neighbours and the other authorities have
their say, and then we approve or refuse. We also decide exemptions
from the zoning rules, we inspect what is actually built, we sign off
finished work, and we deal with building that was never applied for.
who_comes_to_us: >
Homeowners who want a garage, an extension or a new window, and who
have never read a regulation in their life. Architects and
engineering firms who file on behalf of owners; they have to be
approved by us before they may file anything. Neighbours who got a
notice in the post and do not agree with what is planned next door.
The other authorities we are obliged to ask: the road authority, the
fire service, the heritage office, the county. People who ring to say
something is going up behind their fence without permission. And
anyone who wants to sit down with us before they spend eighty
thousand on drawings.
what_we_keep_track_of: >
Pre-application meetings: someone asks for one, we find a time, we
meet, and we write down what we told them so they can hold us to it.
Applications: they arrive, someone checks whether the papers are all
there, and if something is missing we write and ask for it, and the
twelve-week clock stops until they answer. Often we have to ask
twice. When it is complete we send it out to the neighbours and to
the agencies and wait six weeks. Then a case officer writes a
recommendation, and the head of section signs the decision: approved,
approved with conditions, or refused. People can withdraw at any
point, and quite a few do once they hear from the neighbours.
Exemptions: if what someone wants breaks the zoning rules they can
ask for an exemption. It rides along with the application but it is a
decision of its own, and we are not allowed to grant one before the
county has been asked.
Objections: a neighbour who got a notice writes to us within the
hearing period. Each objection belongs to an application. We register
it, the applicant gets to answer it, and the case officer has to
address every single one in the decision, by name.
Hearing answers: we ask an agency, they answer, or they do not, and
when the deadline has passed we go on without them.
Appeals: for three weeks after a decision anyone with an interest can
appeal it. We go through it ourselves first, and if we change our own
mind that is the end of it. If we do not, it goes to the appeals
board, who meet once a month and either uphold us or overturn us.
Inspections: we pick cases and go and look, on site. Either it is as
approved, or we write up what is wrong and set a date for it to be
put right, and then we go back.
Finishing: when the work is done the firm asks for a completion
certificate. If they want to move in before everything is done they
can ask for a temporary permission instead. We check what was
inspected and what is still outstanding before we sign anything.
Illegal building: someone reports it, we go and look, we write to the
owner and they have to explain themselves, and then they either apply
for it properly, take it down, or we fine them weekly until they do.
Approved firms: a firm sends us their registration, their insurance
and what they are qualified for, we check it, and then they are on
the list and may file applications.
who_is_involved: >
The front desk logs what comes in over the counter and on the phone,
and keeps the archive. Four case officers carry the cases. The head
of section signs every decision and every exemption; a case officer
may not sign their own. Two inspectors are out on site most of the
week and write up what they find on a phone in a cold wind. The
appeals board is seven elected politicians who meet on the third
Tuesday of the month and read what we send them. The agencies are
outside the building altogether and only ever answer hearings. The
approved firms file applications and answer objections on behalf of
their clients.
what_slows_us_down: >
The twelve-week clock, and the fact that stopping it and starting it
again is done by hand in a spreadsheet. Applications that arrive
missing half the drawings. Objections that come in on paper and get
stapled to the wrong case. Neighbours ringing to ask what is
happening with the case behind their house, which we are obliged to
tell them and which takes ten minutes every time. Agencies that never
answer at all. And nobody outside this building can see a case
without asking us for it.
## Your last attempt was refused
need "inspection": stages_text names "then we go back", which is not one of its stages
Fix that and return the whole plan again.
```yaml
business: Vestmark kommune - Building and Planning
language: en
contact: { name: Solveig Hauge, email: byggesak@vestmark.example }
about: >
We are the building authority for a municipality of twenty-one
thousand people. Anyone who wants to build, demolish, divide a
property or change what a building is used for has to come to us
first. We check the drawings against the zoning map and the building
regulations, we let the neighbours and the other authorities have
their say, and then we approve or refuse. We also decide exemptions
from the zoning rules, we inspect what is actually built, we sign off
finished work, and we deal with building that was never applied for.
mail: { from: "Vestmark kommune Building and Planning <post@vestmark.example>", reply_to: byggesak@vestmark.example }
does:
- id: check-and-decide
for: application
text: >
We check your drawings against the zoning map and the building
regulations, let the neighbours and the other authorities have
their say, and then approve or refuse. Every case is on the list
here, so you and your neighbours can follow it the whole way,
and object to it or appeal it from its own row.
- id: firms-file-here
for: firm-application
text: >
Approved firms file applications for their clients here, see what
is missing and ask for the completion certificate when the work is done.
doors:
- id: build
who: You want to build, demolish, divide a property or change what a building is used for
- id: firm
who: You are an architect or an engineering firm filing on behalf of owners
invites_by: [head_of_section]
needs:
- id: pre-application-meeting
who: Anyone who wants to sit down with us before they spend money on drawings
wants: A meeting with a case officer, and a written note of what we told them
door: build
lands_in: pre_application_meetings
handled_by: case_officers
stages: [open, scheduled, met, written_up, cancelled]
done_when: [written_up, cancelled]
success: [written_up]
turned_down_from: [open, scheduled]
moves_by: { cancelled: [submitter, case_officers] }
watched_by: [front_desk]
mails: { open: submitter, scheduled: submitter, written_up: submitter, cancelled: submitter }
stages_text: { open: asked for, scheduled: time found, met: meeting held, written_up: written down and sent, cancelled: cancelled }
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: property_address }
- { name: what_you_plan, type: textarea }
- { name: phone, type: tel, optional: true }
- { name: place, type: location, optional: true }
- id: application
who: A homeowner who wants a garage, an extension, a new window or another change to their property
wants: Permission to build, demolish, divide a property or change what a building is used for
door: build
lands_in: applications
handled_by: case_officers
stages: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused, withdrawn]
done_when: [approved, approved_with_conditions, refused, withdrawn]
success: [approved, approved_with_conditions]
skippable: [papers_missing, papers_received]
reached_from:
papers_missing: [open, papers_received, complete, in_hearing]
refused: [recommended]
moves_by:
papers_received: [submitter]
approved: [head_of_section]
approved_with_conditions: [head_of_section]
refused: [head_of_section]
withdrawn: [submitter, case_officers]
watched_by: [public, front_desk, inspectors]
public_states: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused]
mails:
open: submitter
papers_missing: submitter
complete: submitter
in_hearing: submitter
approved: submitter
approved_with_conditions: submitter
refused: submitter
withdrawn: submitter
deadlines: { in_hearing: { days: 42, to: hearing_over } }
stages_text:
open: received
papers_missing: papers missing, clock stopped
papers_received: missing papers sent in
complete: complete, clock running
in_hearing: out to neighbours and agencies
hearing_over: hearing over
recommended: recommendation written
approved: approved
approved_with_conditions: approved with conditions
refused: refused
withdrawn: withdrawn
max_fields: 5
collects:
- { name: name, private: true }
- { name: email, type: email, private: true }
- { name: property_address }
- { name: kind_of_work, type: select, options: [New building, Extension, Garage or outbuilding, Window or facade change, Demolition, Dividing a property, Change of use] }
- { name: what_you_want_to_do, type: textarea }
- { name: enclosed, type: select, multiple: true, optional: true, options: [Site plan, Floor plans, Elevations, Section drawing, Neighbour notices sent, Statement from the owner] }
- { name: phone, type: tel, optional: true, private: true }
- { name: place, type: location, optional: true }
- id: firm-application
who: An approved architect or engineering firm filing on behalf of an owner
wants: To file a building application for a client and see what is missing
door: firm
enters_as: approved_firms
requires: Your firm must be on our list of approved firms before it may file anything.
lands_in: applications
handled_by: case_officers
stages: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused, withdrawn]
done_when: [approved, approved_with_conditions, refused, withdrawn]
success: [approved, approved_with_conditions]
skippable: [papers_missing, papers_received]
reached_from:
papers_missing: [open, papers_received, complete, in_hearing]
refused: [recommended]
moves_by:
papers_received: [submitter]
approved: [head_of_section]
approved_with_conditions: [head_of_section]
refused: [head_of_section]
withdrawn: [submitter, case_officers]
watched_by: [public, front_desk, inspectors]
public_states: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused]
mails:
open: submitter
papers_missing: submitter
complete: submitter
in_hearing: submitter
approved: submitter
approved_with_conditions: submitter
refused: submitter
withdrawn: submitter
deadlines: { in_hearing: { days: 42, to: hearing_over } }
stages_text:
open: received
papers_missing: papers missing, clock stopped
papers_received: missing papers sent in
complete: complete, clock running
in_hearing: out to neighbours and agencies
hearing_over: hearing over
recommended: recommendation written
approved: approved
approved_with_conditions: approved with conditions
refused: refused
withdrawn: withdrawn
max_fields: 6
collects:
- { name: name, private: true }
- { name: email, type: email, private: true }
- { name: property_address }
- { name: kind_of_work, type: select, options: [New building, Extension, Garage or outbuilding, Window or facade change, Demolition, Dividing a property, Change of use] }
- { name: what_you_want_to_do, type: textarea }
- { name: enclosed, type: select, multiple: true, options: [Site plan, Floor plans, Elevations, Section drawing, Neighbour notices sent, Statement from the owner] }
- { name: owner_name, optional: true, private: true }
- { name: phone, type: tel, optional: true, private: true }
- { name: place, type: location, optional: true }
- id: exemption
who: An applicant whose plans break the zoning rules
wants: An exemption from the zoning rules, decided alongside their application
about: application
requires: An application with us; the exemption rides along with it and is asked for from its row on the list of cases.
lands_in: exemptions
handled_by: case_officers
stages: [open, county_asked, county_heard, granted, refused]
done_when: [granted, refused]
success: [granted]
moves_by: { granted: [head_of_section], refused: [head_of_section] }
watched_by: [front_desk]
mails: { open: submitter, county_asked: submitter, granted: submitter, refused: submitter }
deadlines: { county_asked: { days: 42, to: county_heard } }
stages_text: { open: received, county_asked: county asked, county_heard: county has answered or its deadline has passed, granted: granted, refused: refused }
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: rule_it_breaks }
- { name: why_it_should_be_allowed, type: textarea }
- id: objection
who: A neighbour who got a notice in the post and does not agree with what is planned next door
wants: To object to an application and have the objection answered in the decision
about: application
requires: The application must still be out for hearing; objections are taken until the six weeks are up.
lands_in: objections
handled_by: case_officers
stages: [open, registered, answered, addressed]
done_when: [addressed]
success: [addressed]
skippable: [answered]
moves_by: { registered: [front_desk, case_officers], answered: [approved_firms, case_officers] }
watched_by: [front_desk, head_of_section]
mails: { open: submitter, registered: owner, addressed: submitter }
stages_text: { open: received, registered: registered on the case, answered: answered by the applicant, addressed: addressed in the decision }
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: your_property }
- { name: objection, type: textarea }
- { name: phone, type: tel, optional: true }
- id: logged-objection
who: The front desk, when an objection comes in on paper or over the counter
wants: To put the objection on the right case straight away, instead of stapling it to a folder
enters_as: front_desk
lands_in: paper_objections
handled_by: case_officers
stages: [open, registered, answered, addressed]
done_when: [addressed]
success: [addressed]
skippable: [answered]
moves_by: { registered: [front_desk, case_officers], answered: [approved_firms, case_officers] }
watched_by: [front_desk, head_of_section]
stages_text: { open: received, registered: registered on the case, answered: answered by the applicant, addressed: addressed in the decision }
max_fields: 5
collects:
- { name: application_reference }
- { name: name }
- { name: objection, type: textarea }
- { name: received_on, type: date }
- { name: your_property, optional: true }
- { name: phone, type: tel, optional: true }
- id: hearing-request
who: A case officer who is obliged to ask another authority about an application
wants: To ask the road authority, the fire service, the heritage office or the county, and go on when the deadline has passed
enters_as: case_officers
lands_in: hearing_answers
handled_by: case_officers
stages: [open, answered, no_answer]
done_when: [answered, no_answer]
success: [answered]
moves_by: { answered: [agencies, case_officers] }
watched_by: [agencies, front_desk]
deadlines: { open: { days: 42, to: no_answer } }
stages_text: { open: asked, answered: answered, no_answer: deadline passed without an answer }
max_fields: 4
collects:
- { name: application_reference }
- { name: agency, type: select, options: [Road authority, Fire service, Heritage office, County] }
- { name: what_we_ask, type: textarea }
- { name: answer_by, type: date, optional: true }
- id: appeal
who: Anyone with an interest in a decision, the applicant or a neighbour
wants: To appeal a decision we have made
about: application
requires: A decision on the application, made no more than three weeks ago.
lands_in: appeals
handled_by: case_officers
stages: [open, under_review, decision_changed, sent_to_board, upheld, overturned, dismissed]
done_when: [decision_changed, upheld, overturned, dismissed]
success: [decision_changed, upheld, overturned]
turned_down_from: [open, under_review]
reached_from: { decision_changed: [under_review] }
moves_by: { decision_changed: [head_of_section], upheld: [appeals_board], overturned: [appeals_board] }
watched_by: [appeals_board, head_of_section, front_desk]
mails: { open: submitter, decision_changed: submitter, sent_to_board: submitter, upheld: submitter, overturned: submitter, dismissed: submitter }
stages_text: { open: received, under_review: we are going through it ourselves, decision_changed: we changed our own decision, sent_to_board: sent to the appeals board, upheld: decision upheld by the board, overturned: decision overturned by the board, dismissed: dismissed }
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: your_interest, type: select, options: [I am the applicant, I am a neighbour, Other] }
- { name: grounds, type: textarea }
- { name: phone, type: tel, optional: true }
- id: illegal-building-report
who: Someone who sees something going up behind their fence without permission
wants: To tell us, so that we go and look
lands_in: illegal_building
handled_by: case_officers
stages: [open, inspected, owner_written_to, explained, fined, applied_for, taken_down, nothing_illegal]
done_when: [applied_for, taken_down, nothing_illegal]
success: [applied_for, taken_down]
skippable: [fined]
turned_down_from: [open, inspected, explained]
moves_by: { inspected: [inspectors], fined: [head_of_section] }
watched_by: [front_desk, inspectors]
stages_text: { open: reported, inspected: we have been and looked, owner_written_to: owner written to, explained: owner has explained, fined: weekly fine running, applied_for: applied for properly, taken_down: taken down, nothing_illegal: nothing illegal found }
max_fields: 3
collects:
- { name: where }
- { name: what_is_being_built, type: textarea }
- { name: place, type: location, optional: true }
- { name: name, optional: true, private: true }
- { name: phone, type: tel, optional: true, private: true }
- id: logged-report
who: The front desk, when someone rings or comes in about building without permission
wants: To log the report so an inspector goes and looks
enters_as: front_desk
lands_in: illegal_building
handled_by: case_officers
stages: [open, inspected, owner_written_to, explained, fined, applied_for, taken_down, nothing_illegal]
done_when: [applied_for, taken_down, nothing_illegal]
success: [applied_for, taken_down]
skippable: [fined]
turned_down_from: [open, inspected, explained]
moves_by: { inspected: [inspectors], fined: [head_of_section] }
watched_by: [front_desk, inspectors]
stages_text: { open: reported, inspected: we have been and looked, owner_written_to: owner written to, explained: owner has explained, fined: weekly fine running, applied_for: applied for properly, taken_down: taken down, nothing_illegal: nothing illegal found }
max_fields: 3
collects:
- { name: where }
- { name: what_is_being_built, type: textarea }
- { name: place, type: location, optional: true }
- { name: name, optional: true, private: true }
- { name: phone, type: tel, optional: true, private: true }
- id: inspection
who: An inspector on site, writing on a phone in a cold wind
wants: To write up what was found on a case and set a date for what must be put right
enters_as: inspectors
lands_in: inspections
handled_by: inspectors
stages: [open, to_put_right, as_approved]
done_when: [as_approved]
success: [as_approved]
skippable: [to_put_right]
watched_by: [case_officers, head_of_section]
stages_text: { open: inspected, to_put_right: to be put right, then we go back, as_approved: as approved }
max_fields: 3
collects:
- { name: application_reference }
- { name: finding, type: select, options: [As approved, Something is wrong] }
- { name: what_is_wrong, type: textarea, optional: true }
- { name: put_right_by, type: date, optional: true }
- { name: place, type: location, optional: true }
- id: completion-certificate
who: An approved firm whose work on a case is done
wants: A completion certificate for the finished work
door: firm
enters_as: approved_firms
requires: Your firm must be on our list of approved firms, and the application must be approved; have its reference ready.
lands_in: completion_certificates
handled_by: case_officers
stages: [open, checked, issued, refused]
done_when: [issued, refused]
success: [issued]
moves_by: { issued: [head_of_section], refused: [head_of_section] }
watched_by: [inspectors, front_desk]
mails: { open: submitter, issued: submitter, refused: submitter }
stages_text: { open: asked for, checked: inspections and outstanding work checked, issued: certificate signed, refused: refused }
max_fields: 5
collects:
- { name: name }
- { name: email, type: email }
- { name: application_reference }
- { name: finished_on, type: date }
- { name: what_was_built, type: textarea, optional: true }
- { name: still_outstanding, type: textarea, optional: true }
- id: temporary-permission
who: An approved firm whose client wants to move in before everything is done
wants: A temporary permission to use the building
door: firm
enters_as: approved_firms
requires: Your firm must be on our list of approved firms, and the application must be approved; have its reference ready.
lands_in: temporary_permissions
handled_by: case_officers
stages: [open, checked, issued, refused]
done_when: [issued, refused]
success: [issued]
moves_by: { issued: [head_of_section], refused: [head_of_section] }
watched_by: [inspectors, front_desk]
mails: { open: submitter, issued: submitter, refused: submitter }
stages_text: { open: asked for, checked: inspections and outstanding work checked, issued: temporary permission signed, refused: refused }
max_fields: 6
collects:
- { name: name }
- { name: email, type: email }
- { name: application_reference }
- { name: move_in_on, type: date }
- { name: still_outstanding, type: textarea }
- { name: finished_by, type: date, optional: true }
- id: firm-approval
who: An architect or engineering firm that wants to file applications for owners
wants: To be approved by us and put on the list of firms that may file
door: firm
lands_in: approved_firm_requests
handled_by: case_officers
stages: [open, checked, listed, refused]
done_when: [listed, refused]
success: [listed]
moves_by: { listed: [head_of_section], refused: [head_of_section] }
watched_by: [public, front_desk]
public_states: [listed]
mails: { open: submitter, listed: submitter, refused: submitter }
grants: { listed: approved_firms }
stages_text: { open: received, checked: registration, insurance and qualifications checked, listed: on the list, refused: refused }
max_fields: 6
collects:
- { name: firm }
- { name: name, private: true }
- { name: email, type: email, private: true }
- { name: registration_number }
- { name: insurance, private: true }
- { name: qualified_for, type: select, multiple: true, options: [Applying on behalf of owners, Architectural design, Structural engineering, Fire safety design, Geotechnical engineering, Carrying out the work, Independent control] }
- { name: phone, type: tel, optional: true, private: true }
```
Reply with the YAML only, no prose, no code fences.
@@ -0,0 +1,477 @@
business: Vestmark kommune - Building and Planning
language: en
contact: { name: Solveig Hauge, email: byggesak@vestmark.example }
about: >
We are the building authority for a municipality of twenty-one
thousand people. Anyone who wants to build, demolish, divide a
property or change what a building is used for has to come to us
first. We check the drawings against the zoning map and the building
regulations, we let the neighbours and the other authorities have
their say, and then we approve or refuse. We also decide exemptions
from the zoning rules, we inspect what is actually built, we sign off
finished work, and we deal with building that was never applied for.
mail: { from: "Vestmark kommune Building and Planning <post@vestmark.example>", reply_to: byggesak@vestmark.example }
does:
- id: check-and-decide
for: application
text: >
We check your drawings against the zoning map and the building
regulations, let the neighbours and the other authorities have
their say, and then approve or refuse. Every case is on the list
here, so you and your neighbours can follow it the whole way,
and object to it or appeal it from its own row.
- id: firms-file-here
for: firm-application
text: >
Approved firms file applications for their clients here, see what
is missing and ask for the completion certificate when the work is done.
doors:
- id: build
who: You want to build, demolish, divide a property or change what a building is used for
- id: firm
who: You are an architect or an engineering firm filing on behalf of owners
invites_by: [head_of_section]
needs:
- id: pre-application-meeting
who: Anyone who wants to sit down with us before they spend money on drawings
wants: A meeting with a case officer, and a written note of what we told them
door: build
lands_in: pre_application_meetings
handled_by: case_officers
stages: [open, scheduled, met, written_up, cancelled]
done_when: [written_up, cancelled]
success: [written_up]
turned_down_from: [open, scheduled]
moves_by: { cancelled: [submitter, case_officers] }
watched_by: [front_desk]
mails: { open: submitter, scheduled: submitter, written_up: submitter, cancelled: submitter }
stages_text:
open: asked for
scheduled: time found
met: meeting held
written_up: written down and sent
cancelled: cancelled
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: property_address }
- { name: what_you_plan, type: textarea }
- { name: phone, type: tel, optional: true }
- { name: place, type: location, optional: true }
- id: application
who: A homeowner who wants a garage, an extension, a new window or another change to their property
wants: Permission to build, demolish, divide a property or change what a building is used for
door: build
lands_in: applications
handled_by: case_officers
stages: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused, withdrawn]
done_when: [approved, approved_with_conditions, refused, withdrawn]
success: [approved, approved_with_conditions]
skippable: [papers_missing, papers_received]
reached_from:
papers_missing: [open, papers_received, complete, in_hearing]
refused: [recommended]
moves_by:
papers_received: [submitter]
approved: [head_of_section]
approved_with_conditions: [head_of_section]
refused: [head_of_section]
withdrawn: [submitter, case_officers]
watched_by: [public, front_desk, inspectors]
public_states: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused]
mails:
open: submitter
papers_missing: submitter
complete: submitter
in_hearing: submitter
approved: submitter
approved_with_conditions: submitter
refused: submitter
withdrawn: submitter
deadlines: { in_hearing: { days: 42, to: hearing_over } }
stages_text:
open: received
papers_missing: "papers missing, clock stopped"
papers_received: missing papers sent in
complete: "complete, clock running"
in_hearing: out to neighbours and agencies
hearing_over: hearing over
recommended: recommendation written
approved: approved
approved_with_conditions: approved with conditions
refused: refused
withdrawn: withdrawn
max_fields: 5
collects:
- { name: name, private: true }
- { name: email, type: email, private: true }
- { name: property_address }
- { name: kind_of_work, type: select, options: [New building, Extension, Garage or outbuilding, Window or facade change, Demolition, Dividing a property, Change of use] }
- { name: what_you_want_to_do, type: textarea }
- { name: enclosed, type: select, multiple: true, optional: true, options: [Site plan, Floor plans, Elevations, Section drawing, Neighbour notices sent, Statement from the owner] }
- { name: phone, type: tel, optional: true, private: true }
- { name: place, type: location, optional: true }
- id: firm-application
who: An approved architect or engineering firm filing on behalf of an owner
wants: To file a building application for a client and see what is missing
door: firm
enters_as: approved_firms
requires: Your firm must be on our list of approved firms before it may file anything.
lands_in: applications
handled_by: case_officers
stages: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused, withdrawn]
done_when: [approved, approved_with_conditions, refused, withdrawn]
success: [approved, approved_with_conditions]
skippable: [papers_missing, papers_received]
reached_from:
papers_missing: [open, papers_received, complete, in_hearing]
refused: [recommended]
moves_by:
papers_received: [submitter]
approved: [head_of_section]
approved_with_conditions: [head_of_section]
refused: [head_of_section]
withdrawn: [submitter, case_officers]
watched_by: [public, front_desk, inspectors]
public_states: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused]
mails:
open: submitter
papers_missing: submitter
complete: submitter
in_hearing: submitter
approved: submitter
approved_with_conditions: submitter
refused: submitter
withdrawn: submitter
deadlines: { in_hearing: { days: 42, to: hearing_over } }
stages_text:
open: received
papers_missing: "papers missing, clock stopped"
papers_received: missing papers sent in
complete: "complete, clock running"
in_hearing: out to neighbours and agencies
hearing_over: hearing over
recommended: recommendation written
approved: approved
approved_with_conditions: approved with conditions
refused: refused
withdrawn: withdrawn
max_fields: 6
collects:
- { name: name, private: true }
- { name: email, type: email, private: true }
- { name: property_address }
- { name: kind_of_work, type: select, options: [New building, Extension, Garage or outbuilding, Window or facade change, Demolition, Dividing a property, Change of use] }
- { name: what_you_want_to_do, type: textarea }
- { name: enclosed, type: select, multiple: true, options: [Site plan, Floor plans, Elevations, Section drawing, Neighbour notices sent, Statement from the owner] }
- { name: owner_name, optional: true, private: true }
- { name: phone, type: tel, optional: true, private: true }
- { name: place, type: location, optional: true }
- id: exemption
who: An applicant whose plans break the zoning rules
wants: An exemption from the zoning rules, decided alongside their application
about: application
requires: An application with us; the exemption rides along with it and is asked for from its row on the list of cases.
lands_in: exemptions
handled_by: case_officers
stages: [open, county_asked, county_heard, granted, refused]
done_when: [granted, refused]
success: [granted]
moves_by: { granted: [head_of_section], refused: [head_of_section] }
watched_by: [front_desk]
mails: { open: submitter, county_asked: submitter, granted: submitter, refused: submitter }
deadlines: { county_asked: { days: 42, to: county_heard } }
stages_text:
open: received
county_asked: county asked
county_heard: county has answered or its deadline has passed
granted: granted
refused: refused
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: rule_it_breaks }
- { name: why_it_should_be_allowed, type: textarea }
- id: objection
who: A neighbour who got a notice in the post and does not agree with what is planned next door
wants: To object to an application and have the objection answered in the decision
about: application
requires: The application must still be out for hearing; objections are taken until the six weeks are up.
lands_in: objections
handled_by: case_officers
stages: [open, registered, answered, addressed]
done_when: [addressed]
success: [addressed]
skippable: [answered]
moves_by: { registered: [front_desk, case_officers], answered: [approved_firms, case_officers] }
watched_by: [front_desk, head_of_section]
mails: { open: submitter, registered: owner, addressed: submitter }
stages_text:
open: received
registered: registered on the case
answered: answered by the applicant
addressed: addressed in the decision
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: your_property }
- { name: objection, type: textarea }
- { name: phone, type: tel, optional: true }
- id: logged-objection
who: The front desk, when an objection comes in on paper or over the counter
wants: To put the objection on the right case straight away, instead of stapling it to a folder
enters_as: front_desk
lands_in: paper_objections
handled_by: case_officers
stages: [open, registered, answered, addressed]
done_when: [addressed]
success: [addressed]
skippable: [answered]
moves_by: { registered: [front_desk, case_officers], answered: [approved_firms, case_officers] }
watched_by: [front_desk, head_of_section]
stages_text:
open: received
registered: registered on the case
answered: answered by the applicant
addressed: addressed in the decision
max_fields: 5
collects:
- { name: application_reference }
- { name: name }
- { name: objection, type: textarea }
- { name: received_on, type: date }
- { name: your_property, optional: true }
- { name: phone, type: tel, optional: true }
- id: hearing-request
who: A case officer who is obliged to ask another authority about an application
wants: To ask the road authority, the fire service, the heritage office or the county, and go on when the deadline has passed
enters_as: case_officers
lands_in: hearing_answers
handled_by: case_officers
stages: [open, answered, no_answer]
done_when: [answered, no_answer]
success: [answered]
moves_by: { answered: [agencies, case_officers] }
watched_by: [agencies, front_desk]
deadlines: { open: { days: 42, to: no_answer } }
stages_text:
open: asked
answered: answered
no_answer: deadline passed without an answer
max_fields: 4
collects:
- { name: application_reference }
- { name: agency, type: select, options: [Road authority, Fire service, Heritage office, County] }
- { name: what_we_ask, type: textarea }
- { name: answer_by, type: date, optional: true }
- id: appeal
who: Anyone with an interest in a decision, the applicant or a neighbour
wants: To appeal a decision we have made
about: application
requires: A decision on the application, made no more than three weeks ago.
lands_in: appeals
handled_by: case_officers
stages: [open, under_review, decision_changed, sent_to_board, upheld, overturned, dismissed]
done_when: [decision_changed, upheld, overturned, dismissed]
success: [decision_changed, upheld, overturned]
turned_down_from: [open, under_review]
reached_from: { decision_changed: [under_review] }
moves_by: { decision_changed: [head_of_section], upheld: [appeals_board], overturned: [appeals_board] }
watched_by: [appeals_board, head_of_section, front_desk]
mails: { open: submitter, decision_changed: submitter, sent_to_board: submitter, upheld: submitter, overturned: submitter, dismissed: submitter }
stages_text:
open: received
under_review: we are going through it ourselves
decision_changed: we changed our own decision
sent_to_board: sent to the appeals board
upheld: decision upheld by the board
overturned: decision overturned by the board
dismissed: dismissed
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: your_interest, type: select, options: [I am the applicant, I am a neighbour, Other] }
- { name: grounds, type: textarea }
- { name: phone, type: tel, optional: true }
- id: illegal-building-report
who: Someone who sees something going up behind their fence without permission
wants: To tell us, so that we go and look
lands_in: illegal_building
handled_by: case_officers
stages: [open, inspected, owner_written_to, explained, fined, applied_for, taken_down, nothing_illegal]
done_when: [applied_for, taken_down, nothing_illegal]
success: [applied_for, taken_down]
skippable: [fined]
turned_down_from: [open, inspected, explained]
moves_by: { inspected: [inspectors], fined: [head_of_section] }
watched_by: [front_desk, inspectors]
stages_text:
open: reported
inspected: we have been and looked
owner_written_to: owner written to
explained: owner has explained
fined: weekly fine running
applied_for: applied for properly
taken_down: taken down
nothing_illegal: nothing illegal found
max_fields: 3
collects:
- { name: where }
- { name: what_is_being_built, type: textarea }
- { name: place, type: location, optional: true }
- { name: name, optional: true, private: true }
- { name: phone, type: tel, optional: true, private: true }
- id: logged-report
who: The front desk, when someone rings or comes in about building without permission
wants: To log the report so an inspector goes and looks
enters_as: front_desk
lands_in: illegal_building
handled_by: case_officers
stages: [open, inspected, owner_written_to, explained, fined, applied_for, taken_down, nothing_illegal]
done_when: [applied_for, taken_down, nothing_illegal]
success: [applied_for, taken_down]
skippable: [fined]
turned_down_from: [open, inspected, explained]
moves_by: { inspected: [inspectors], fined: [head_of_section] }
watched_by: [front_desk, inspectors]
stages_text:
open: reported
inspected: we have been and looked
owner_written_to: owner written to
explained: owner has explained
fined: weekly fine running
applied_for: applied for properly
taken_down: taken down
nothing_illegal: nothing illegal found
max_fields: 3
collects:
- { name: where }
- { name: what_is_being_built, type: textarea }
- { name: place, type: location, optional: true }
- { name: name, optional: true, private: true }
- { name: phone, type: tel, optional: true, private: true }
- id: inspection
who: An inspector on site, writing on a phone in a cold wind
wants: To write up what was found on a case and set a date for what must be put right
enters_as: inspectors
lands_in: inspections
handled_by: inspectors
stages: [open, to_put_right, as_approved]
done_when: [as_approved]
success: [as_approved]
skippable: [to_put_right]
watched_by: [case_officers, head_of_section]
stages_text:
open: inspected
to_put_right: "to be put right, then we go back"
as_approved: as approved
max_fields: 3
collects:
- { name: application_reference }
- { name: finding, type: select, options: [As approved, Something is wrong] }
- { name: what_is_wrong, type: textarea, optional: true }
- { name: put_right_by, type: date, optional: true }
- { name: place, type: location, optional: true }
- id: completion-certificate
who: An approved firm whose work on a case is done
wants: A completion certificate for the finished work
door: firm
enters_as: approved_firms
requires: Your firm must be on our list of approved firms, and the application must be approved; have its reference ready.
lands_in: completion_certificates
handled_by: case_officers
stages: [open, checked, issued, refused]
done_when: [issued, refused]
success: [issued]
moves_by: { issued: [head_of_section], refused: [head_of_section] }
watched_by: [inspectors, front_desk]
mails: { open: submitter, issued: submitter, refused: submitter }
stages_text:
open: asked for
checked: inspections and outstanding work checked
issued: certificate signed
refused: refused
max_fields: 5
collects:
- { name: name }
- { name: email, type: email }
- { name: application_reference }
- { name: finished_on, type: date }
- { name: what_was_built, type: textarea, optional: true }
- { name: still_outstanding, type: textarea, optional: true }
- id: temporary-permission
who: An approved firm whose client wants to move in before everything is done
wants: A temporary permission to use the building
door: firm
enters_as: approved_firms
requires: Your firm must be on our list of approved firms, and the application must be approved; have its reference ready.
lands_in: temporary_permissions
handled_by: case_officers
stages: [open, checked, issued, refused]
done_when: [issued, refused]
success: [issued]
moves_by: { issued: [head_of_section], refused: [head_of_section] }
watched_by: [inspectors, front_desk]
mails: { open: submitter, issued: submitter, refused: submitter }
stages_text:
open: asked for
checked: inspections and outstanding work checked
issued: temporary permission signed
refused: refused
max_fields: 6
collects:
- { name: name }
- { name: email, type: email }
- { name: application_reference }
- { name: move_in_on, type: date }
- { name: still_outstanding, type: textarea }
- { name: finished_by, type: date, optional: true }
- id: firm-approval
who: An architect or engineering firm that wants to file applications for owners
wants: To be approved by us and put on the list of firms that may file
door: firm
lands_in: approved_firm_requests
handled_by: case_officers
stages: [open, checked, listed, refused]
done_when: [listed, refused]
success: [listed]
moves_by: { listed: [head_of_section], refused: [head_of_section] }
watched_by: [public, front_desk]
public_states: [listed]
mails: { open: submitter, listed: submitter, refused: submitter }
grants: { listed: approved_firms }
stages_text:
open: received
checked: "registration, insurance and qualifications checked"
listed: on the list
refused: refused
max_fields: 6
collects:
- { name: firm }
- { name: name, private: true }
- { name: email, type: email, private: true }
- { name: registration_number }
- { name: insurance, private: true }
- { name: qualified_for, type: select, multiple: true, options: [Applying on behalf of owners, Architectural design, Structural engineering, Fire safety design, Geotechnical engineering, Carrying out the work, Independent control] }
- { name: phone, type: tel, optional: true, private: true }
+549
View File
@@ -0,0 +1,549 @@
business: Vestmark kommune - Building and Planning
language: en
contact: { name: Solveig Hauge, email: byggesak@vestmark.example }
about: >
We are the building authority for a municipality of twenty-one
thousand people. Anyone who wants to build, demolish, divide a
property or change what a building is used for has to come to us
first. We check the drawings against the zoning map and the building
regulations, we let the neighbours and the other authorities have
their say, and then we approve or refuse. We also decide exemptions
from the zoning rules, we inspect what is actually built, we sign off
finished work, and we deal with building that was never applied for.
mail: { from: "Vestmark kommune Building and Planning <post@vestmark.example>", reply_to: byggesak@vestmark.example }
does:
- id: check-and-decide
for: application
text: >
We check your drawings against the zoning map and the building
regulations, let the neighbours and the other authorities have
their say, and then approve or refuse. Every case is on the list
here, so you and your neighbours can follow it the whole way,
and object to it or appeal it from its own row.
- id: firms-file-here
for: firm-application
text: >
Approved firms file applications for their clients here, see what
is missing and ask for the completion certificate when the work is done.
doors:
- id: build
who: You want to build, demolish, divide a property or change what a building is used for
- id: firm
who: You are an architect or an engineering firm filing on behalf of owners
invites_by: [head_of_section]
needs:
- id: pre-application-meeting
who: Anyone who wants to sit down with us before they spend money on drawings
wants: A meeting with a case officer, and a written note of what we told them
door: build
lands_in: pre_application_meetings
handled_by: case_officers
stages: [open, scheduled, met, written_up, cancelled]
done_when: [written_up, cancelled]
success: [written_up]
turned_down_from: [open, scheduled]
moves_by: { cancelled: [submitter, case_officers] }
watched_by: [front_desk]
mails: { open: submitter, scheduled: submitter, written_up: submitter, cancelled: submitter }
stages_text:
open: asked for
scheduled: time found
met: meeting held
written_up: written down and sent
cancelled: cancelled
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: property_address }
- { name: what_you_plan, type: textarea }
- { name: phone, type: tel, optional: true }
- { name: place, type: location, optional: true }
- id: application
who: A homeowner who wants a garage, an extension, a new window or another change to their property
wants: Permission to build, demolish, divide a property or change what a building is used for
door: build
lands_in: applications
handled_by: case_officers
stages: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused, withdrawn]
done_when: [approved, approved_with_conditions, refused, withdrawn]
success: [approved, approved_with_conditions]
skippable: [papers_missing, papers_received]
reached_from:
papers_missing: [open, papers_received, complete, in_hearing]
refused: [recommended]
moves_by:
papers_received: [submitter]
approved: [head_of_section]
approved_with_conditions: [head_of_section]
refused: [head_of_section]
withdrawn: [submitter, case_officers]
watched_by: [public, front_desk, inspectors]
public_states: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused]
mails:
open: submitter
papers_missing: submitter
complete: submitter
in_hearing: submitter
approved: submitter
approved_with_conditions: submitter
refused: submitter
withdrawn: submitter
deadlines: { in_hearing: { days: 42, to: hearing_over } }
stages_text:
open: received
papers_missing: "papers missing, clock stopped"
papers_received: missing papers sent in
complete: "complete, clock running"
in_hearing: out to neighbours and agencies
hearing_over: hearing over
recommended: recommendation written
approved: approved
approved_with_conditions: approved with conditions
refused: refused
withdrawn: withdrawn
max_fields: 5
collects:
- { name: name, private: true }
- { name: email, type: email, private: true }
- { name: property_address }
- { name: kind_of_work, type: select, options: [New building, Extension, Garage or outbuilding, Window or facade change, Demolition, Dividing a property, Change of use] }
- { name: what_you_want_to_do, type: textarea }
- { name: enclosed, type: select, multiple: true, optional: true, options: [Site plan, Floor plans, Elevations, Section drawing, Neighbour notices sent, Statement from the owner] }
- { name: phone, type: tel, optional: true, private: true }
- { name: place, type: location, optional: true }
- id: firm-application
who: An approved architect or engineering firm filing on behalf of an owner
wants: To file a building application for a client and see what is missing
door: firm
enters_as: approved_firms
requires: Your firm must be on our list of approved firms before it may file anything.
lands_in: applications
handled_by: case_officers
stages: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused, withdrawn]
done_when: [approved, approved_with_conditions, refused, withdrawn]
success: [approved, approved_with_conditions]
skippable: [papers_missing, papers_received]
reached_from:
papers_missing: [open, papers_received, complete, in_hearing]
refused: [recommended]
moves_by:
papers_received: [submitter]
approved: [head_of_section]
approved_with_conditions: [head_of_section]
refused: [head_of_section]
withdrawn: [submitter, case_officers]
watched_by: [public, front_desk, inspectors]
public_states: [open, papers_missing, papers_received, complete, in_hearing, hearing_over, recommended, approved, approved_with_conditions, refused]
mails:
open: submitter
papers_missing: submitter
complete: submitter
in_hearing: submitter
approved: submitter
approved_with_conditions: submitter
refused: submitter
withdrawn: submitter
deadlines: { in_hearing: { days: 42, to: hearing_over } }
stages_text:
open: received
papers_missing: "papers missing, clock stopped"
papers_received: missing papers sent in
complete: "complete, clock running"
in_hearing: out to neighbours and agencies
hearing_over: hearing over
recommended: recommendation written
approved: approved
approved_with_conditions: approved with conditions
refused: refused
withdrawn: withdrawn
max_fields: 6
collects:
- { name: name, private: true }
- { name: email, type: email, private: true }
- { name: property_address }
- { name: kind_of_work, type: select, options: [New building, Extension, Garage or outbuilding, Window or facade change, Demolition, Dividing a property, Change of use] }
- { name: what_you_want_to_do, type: textarea }
- { name: enclosed, type: select, multiple: true, options: [Site plan, Floor plans, Elevations, Section drawing, Neighbour notices sent, Statement from the owner] }
- { name: owner_name, optional: true, private: true }
- { name: phone, type: tel, optional: true, private: true }
- { name: place, type: location, optional: true }
- id: exemption
who: An applicant whose plans break the zoning rules
wants: An exemption from the zoning rules, decided alongside their application
about: application
requires: An application with us; the exemption rides along with it and is asked for from its row on the list of cases.
lands_in: exemptions
handled_by: case_officers
stages: [open, county_asked, county_heard, granted, refused]
done_when: [granted, refused]
success: [granted]
moves_by: { granted: [head_of_section], refused: [head_of_section] }
watched_by: [front_desk]
mails: { open: submitter, county_asked: submitter, granted: submitter, refused: submitter }
deadlines: { county_asked: { days: 42, to: county_heard } }
stages_text:
open: received
county_asked: county asked
county_heard: county has answered or its deadline has passed
granted: granted
refused: refused
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: rule_it_breaks }
- { name: why_it_should_be_allowed, type: textarea }
- id: objection
who: A neighbour who got a notice in the post and does not agree with what is planned next door
wants: To object to an application and have the objection answered in the decision
about: application
requires: The application must still be out for hearing; objections are taken until the six weeks are up.
lands_in: objections
handled_by: case_officers
stages: [open, registered, answered, addressed]
done_when: [addressed]
success: [addressed]
skippable: [answered]
moves_by: { registered: [front_desk, case_officers], answered: [approved_firms, case_officers] }
watched_by: [front_desk, head_of_section]
mails: { open: submitter, registered: owner, addressed: submitter }
stages_text:
open: received
registered: registered on the case
answered: answered by the applicant
addressed: addressed in the decision
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: your_property }
- { name: objection, type: textarea }
- { name: phone, type: tel, optional: true }
- id: logged-objection
who: The front desk, when an objection comes in on paper or over the counter
wants: To put the objection on the right case straight away, instead of stapling it to a folder
enters_as: front_desk
lands_in: paper_objections
handled_by: case_officers
stages: [open, registered, answered, addressed]
done_when: [addressed]
success: [addressed]
skippable: [answered]
moves_by: { registered: [front_desk, case_officers], answered: [approved_firms, case_officers] }
watched_by: [front_desk, head_of_section]
stages_text:
open: received
registered: registered on the case
answered: answered by the applicant
addressed: addressed in the decision
max_fields: 5
collects:
- { name: application_reference }
- { name: name }
- { name: objection, type: textarea }
- { name: received_on, type: date }
- { name: your_property, optional: true }
- { name: phone, type: tel, optional: true }
- id: hearing-request
who: A case officer who is obliged to ask another authority about an application
wants: To ask the road authority, the fire service, the heritage office or the county, and go on when the deadline has passed
enters_as: case_officers
lands_in: hearing_answers
handled_by: case_officers
stages: [open, answered, no_answer]
done_when: [answered, no_answer]
success: [answered]
moves_by: { answered: [agencies, case_officers] }
watched_by: [agencies, front_desk]
deadlines: { open: { days: 42, to: no_answer } }
stages_text:
open: asked
answered: answered
no_answer: deadline passed without an answer
max_fields: 4
collects:
- { name: application_reference }
- { name: agency, type: select, options: [Road authority, Fire service, Heritage office, County] }
- { name: what_we_ask, type: textarea }
- { name: answer_by, type: date, optional: true }
- id: appeal
who: Anyone with an interest in a decision, the applicant or a neighbour
wants: To appeal a decision we have made
about: application
requires: A decision on the application, made no more than three weeks ago.
lands_in: appeals
handled_by: case_officers
stages: [open, under_review, decision_changed, sent_to_board, upheld, overturned, dismissed]
done_when: [decision_changed, upheld, overturned, dismissed]
success: [decision_changed, upheld, overturned]
turned_down_from: [open, under_review]
reached_from: { decision_changed: [under_review] }
moves_by: { decision_changed: [head_of_section], upheld: [appeals_board], overturned: [appeals_board] }
watched_by: [appeals_board, head_of_section, front_desk]
mails: { open: submitter, decision_changed: submitter, sent_to_board: submitter, upheld: submitter, overturned: submitter, dismissed: submitter }
stages_text:
open: received
under_review: we are going through it ourselves
decision_changed: we changed our own decision
sent_to_board: sent to the appeals board
upheld: decision upheld by the board
overturned: decision overturned by the board
dismissed: dismissed
max_fields: 4
collects:
- { name: name }
- { name: email, type: email }
- { name: your_interest, type: select, options: [I am the applicant, I am a neighbour, Other] }
- { name: grounds, type: textarea }
- { name: phone, type: tel, optional: true }
- id: illegal-building-report
who: Someone who sees something going up behind their fence without permission
wants: To tell us, so that we go and look
lands_in: illegal_building
handled_by: case_officers
stages: [open, inspected, owner_written_to, explained, fined, applied_for, taken_down, nothing_illegal]
done_when: [applied_for, taken_down, nothing_illegal]
success: [applied_for, taken_down]
skippable: [fined]
turned_down_from: [open, inspected, explained]
moves_by: { inspected: [inspectors], fined: [head_of_section] }
watched_by: [front_desk, inspectors]
stages_text:
open: reported
inspected: we have been and looked
owner_written_to: owner written to
explained: owner has explained
fined: weekly fine running
applied_for: applied for properly
taken_down: taken down
nothing_illegal: nothing illegal found
max_fields: 3
collects:
- { name: where }
- { name: what_is_being_built, type: textarea }
- { name: place, type: location, optional: true }
- { name: name, optional: true, private: true }
- { name: phone, type: tel, optional: true, private: true }
- id: logged-report
who: The front desk, when someone rings or comes in about building without permission
wants: To log the report so an inspector goes and looks
enters_as: front_desk
lands_in: illegal_building
handled_by: case_officers
stages: [open, inspected, owner_written_to, explained, fined, applied_for, taken_down, nothing_illegal]
done_when: [applied_for, taken_down, nothing_illegal]
success: [applied_for, taken_down]
skippable: [fined]
turned_down_from: [open, inspected, explained]
moves_by: { inspected: [inspectors], fined: [head_of_section] }
watched_by: [front_desk, inspectors]
stages_text:
open: reported
inspected: we have been and looked
owner_written_to: owner written to
explained: owner has explained
fined: weekly fine running
applied_for: applied for properly
taken_down: taken down
nothing_illegal: nothing illegal found
max_fields: 3
collects:
- { name: where }
- { name: what_is_being_built, type: textarea }
- { name: place, type: location, optional: true }
- { name: name, optional: true, private: true }
- { name: phone, type: tel, optional: true, private: true }
- id: inspection
who: An inspector on site, writing on a phone in a cold wind
wants: To write up what was found on a case and set a date for what must be put right
enters_as: inspectors
lands_in: inspections
handled_by: inspectors
stages: [open, to_put_right, as_approved]
done_when: [as_approved]
success: [as_approved]
skippable: [to_put_right]
watched_by: [case_officers, head_of_section]
stages_text:
open: inspected
to_put_right: "to be put right, then we go back"
as_approved: as approved
max_fields: 3
collects:
- { name: application_reference }
- { name: finding, type: select, options: [As approved, Something is wrong] }
- { name: what_is_wrong, type: textarea, optional: true }
- { name: put_right_by, type: date, optional: true }
- { name: place, type: location, optional: true }
- id: completion-certificate
who: An approved firm whose work on a case is done
wants: A completion certificate for the finished work
door: firm
enters_as: approved_firms
requires: Your firm must be on our list of approved firms, and the application must be approved; have its reference ready.
lands_in: completion_certificates
handled_by: case_officers
stages: [open, checked, issued, refused]
done_when: [issued, refused]
success: [issued]
moves_by: { issued: [head_of_section], refused: [head_of_section] }
watched_by: [inspectors, front_desk]
mails: { open: submitter, issued: submitter, refused: submitter }
stages_text:
open: asked for
checked: inspections and outstanding work checked
issued: certificate signed
refused: refused
max_fields: 5
collects:
- { name: name }
- { name: email, type: email }
- { name: application_reference }
- { name: finished_on, type: date }
- { name: what_was_built, type: textarea, optional: true }
- { name: still_outstanding, type: textarea, optional: true }
- id: temporary-permission
who: An approved firm whose client wants to move in before everything is done
wants: A temporary permission to use the building
door: firm
enters_as: approved_firms
requires: Your firm must be on our list of approved firms, and the application must be approved; have its reference ready.
lands_in: temporary_permissions
handled_by: case_officers
stages: [open, checked, issued, refused]
done_when: [issued, refused]
success: [issued]
moves_by: { issued: [head_of_section], refused: [head_of_section] }
watched_by: [inspectors, front_desk]
mails: { open: submitter, issued: submitter, refused: submitter }
stages_text:
open: asked for
checked: inspections and outstanding work checked
issued: temporary permission signed
refused: refused
max_fields: 6
collects:
- { name: name }
- { name: email, type: email }
- { name: application_reference }
- { name: move_in_on, type: date }
- { name: still_outstanding, type: textarea }
- { name: finished_by, type: date, optional: true }
- id: firm-approval
who: An architect or engineering firm that wants to file applications for owners
wants: To be approved by us and put on the list of firms that may file
door: firm
lands_in: approved_firm_requests
handled_by: case_officers
stages: [open, checked, listed, refused]
done_when: [listed, refused]
success: [listed]
moves_by: { listed: [head_of_section], refused: [head_of_section] }
watched_by: [public, front_desk]
public_states: [listed]
mails: { open: submitter, listed: submitter, refused: submitter }
grants: { listed: approved_firms }
stages_text:
open: received
checked: "registration, insurance and qualifications checked"
listed: on the list
refused: refused
max_fields: 6
collects:
- { name: firm }
- { name: name, private: true }
- { name: email, type: email, private: true }
- { name: registration_number }
- { name: insurance, private: true }
- { name: qualified_for, type: select, multiple: true, options: [Applying on behalf of owners, Architectural design, Structural engineering, Fire safety design, Geotechnical engineering, Carrying out the work, Independent control] }
- { name: phone, type: tel, optional: true, private: true }
# Held out from every model that writes words.
personas:
- id: garage-owner
need: pre-application-meeting
text: We want to put a double garage where the old shed is. Before I pay an architect I'd like to know whether you'll even allow it, because the neighbour says it's too close to the road.
- id: shop-to-flats
need: pre-application-meeting
text: I own the old grocery on Torget and want to make four flats out of it. There are a lot of questions - parking, fire, the facade is listed. Can we sit down with someone?
- id: firm-files-extension
need: firm-application
text: We are the responsible applicant for an extension at Bjorkeveien 14. Drawings, site plan and the neighbour notices are all ready. We file maybe forty of these a year.
- id: owner-small-window
need: application
text: I want to put a dormer window in my roof. The man at the counter said I have to apply even though it's small.
- id: missing-drawings
need: firm-application
text: You wrote that our section drawing is missing and the case is on hold. I've got it here now, where do I send it so the clock starts again?
- id: too-close-to-boundary
need: exemption
text: The garage ends up one and a half metres from the boundary and the plan says four. We are asking you to allow it anyway - the ground falls away steeply everywhere else on the plot.
- id: neighbour-view
need: objection
text: I got a notice about the extension at number 14. It takes the afternoon sun off my entire terrace and I want that on the record before you decide anything.
- id: neighbour-parking
need: objection
text: The flats they want to build in the old grocery have four parking places for four flats and everyone here already parks on the street. I object.
- id: road-authority
need: hearing-request
text: 'Regarding your case 2026/418: the access onto the county road is within the sight line and we cannot accept it as drawn. Our formal reply is attached.'
- id: fire-service
need: hearing-request
text: We have looked at the conversion on Torget. We have no objection provided the stairwell is upgraded. Reference your case 2026/501.
- id: refused-applicant
need: appeal
text: You refused our exemption on the ninth. We don't accept the reasoning - you've allowed the same thing twice in the same street. We're appealing.
- id: neighbour-appeals
need: appeal
text: You approved the extension next door even though I objected. I'm appealing the decision. What do I need to send?
- id: board-member
need: appeal
text: I sit on the appeals board. I need the case, our own decision, and what the neighbours wrote, before Tuesday.
- id: inspector-on-roof
need: inspection
text: I'm up on the scaffold at Bjorkeveien. The fire wall isn't built to the drawing at all. I've got gloves on and it's blowing. I want this logged before I climb down.
- id: inspector-all-good
need: inspection
text: Been out at Torget. Everything is as approved. Nothing to report but I have to record that I was there.
- id: firm-wants-certificate
need: completion-certificate
text: The work at Bjorkeveien 14 is finished and inspected. We're asking for the completion certificate so the owners can get their mortgage released.
- id: wants-to-move-in
need: temporary-permission
text: The house is done apart from the outside steps, which we can't pour until spring. The family has sold their flat. Can we get a temporary permission to move in?
- id: something-behind-fence
need: illegal-building-report
text: There's a large structure going up behind the fence at Solbakken 7. Nobody has had a notice about it and it's been going on for two weeks.
- id: owner-explains
need: illegal-building-report
text: I got your letter about the terrace. I genuinely did not know it needed an application, it's been there since we moved in. What happens now?
- id: new-firm
need: firm-approval
text: We are a three-person architecture firm that has just started. We want to be approved so we can file applications for our clients in your municipality.
- id: firm-insurance-lapsed
need: firm-approval
text: You wrote that our liability insurance certificate has expired. We have renewed it, here it is.
- id: counter-phone-call
need: log-counter-enquiry
text: A woman rang about the case behind her house. Wants to know where it stands. I'm at the counter and there's a queue - I need to write it down and send it to whoever has that case.
- id: where-is-my-case
need: case-status-enquiry
text: I sent in my application five weeks ago and I've heard nothing. Is anyone looking at it? Is it in the six weeks with the neighbours or is it waiting on me?
@@ -0,0 +1,611 @@
aggregates:
- bucket: appeals
initial: open
states:
open:
event: received
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Open'
body: |-
Hello {name},
We have received what you sent about To appeal a decision we have made.
Solveig Hauge at byggesak@vestmark.example
under_review:
event: under_review
decision_changed:
event: decision_changed
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Decision changed'
body: |-
Hello {name},
What you sent about To appeal a decision we have made is now we changed our own decision.
Solveig Hauge at byggesak@vestmark.example
sent_to_board:
event: sent_to_board
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Sent to board'
body: |-
Hello {name},
What you sent about To appeal a decision we have made is now sent to the appeals board.
Solveig Hauge at byggesak@vestmark.example
upheld:
event: upheld
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Upheld'
body: |-
Hello {name},
What you sent about To appeal a decision we have made is now decision upheld by the board.
Solveig Hauge at byggesak@vestmark.example
overturned:
event: overturned
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Overturned'
body: |-
Hello {name},
What you sent about To appeal a decision we have made is now decision overturned by the board.
Solveig Hauge at byggesak@vestmark.example
dismissed:
event: dismissed
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Dismissed'
body: |-
Hello {name},
What you sent about To appeal a decision we have made is now dismissed.
Solveig Hauge at byggesak@vestmark.example
transitions:
open:
- under_review
- dismissed
sent_to_board:
- upheld
- overturned
under_review:
- sent_to_board
- dismissed
- decision_changed
- bucket: applications
initial: open
states:
open:
event: received
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Open'
body: |-
Hello {name},
We have received what you sent about Permission to build, demolish, divide a property or change what a building is used for.
What you can do next: {site}/decide/application?chain={chain}&email={email}
Solveig Hauge at byggesak@vestmark.example
papers_missing:
event: papers_missing
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Papers missing'
body: |-
Hello {name},
What you sent about Permission to build, demolish, divide a property or change what a building is used for is now papers missing, clock stopped.
What you can do next: {site}/decide/application?chain={chain}&email={email}
Solveig Hauge at byggesak@vestmark.example
papers_received:
event: papers_received
complete:
event: complete
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Complete'
body: |-
Hello {name},
What you sent about Permission to build, demolish, divide a property or change what a building is used for is now complete, clock running.
What you can do next: {site}/decide/application?chain={chain}&email={email}
Solveig Hauge at byggesak@vestmark.example
in_hearing:
event: in_hearing
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: In hearing'
body: |-
Hello {name},
What you sent about Permission to build, demolish, divide a property or change what a building is used for is now out to neighbours and agencies.
What you can do next: {site}/decide/application?chain={chain}&email={email}
Solveig Hauge at byggesak@vestmark.example
after:
days: 42
to: hearing_over
hearing_over:
event: hearing_over
recommended:
event: recommended
approved:
event: approved
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Approved'
body: |-
Hello {name},
What you sent about Permission to build, demolish, divide a property or change what a building is used for is now approved.
Solveig Hauge at byggesak@vestmark.example
approved_with_conditions:
event: approved_with_conditions
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Approved with conditions'
body: |-
Hello {name},
What you sent about Permission to build, demolish, divide a property or change what a building is used for is now approved with conditions.
Solveig Hauge at byggesak@vestmark.example
refused:
event: refused
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Refused'
body: |-
Hello {name},
What you sent about Permission to build, demolish, divide a property or change what a building is used for is now refused.
Solveig Hauge at byggesak@vestmark.example
withdrawn:
event: withdrawn
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Withdrawn'
body: |-
Hello {name},
What you sent about Permission to build, demolish, divide a property or change what a building is used for is now withdrawn.
Solveig Hauge at byggesak@vestmark.example
transitions:
complete:
- in_hearing
- withdrawn
- papers_missing
hearing_over:
- recommended
- withdrawn
in_hearing:
- hearing_over
- withdrawn
- papers_missing
open:
- papers_received
- complete
- withdrawn
- papers_missing
papers_missing:
- papers_received
- complete
- withdrawn
papers_received:
- complete
- withdrawn
- papers_missing
recommended:
- approved
- approved_with_conditions
- withdrawn
- refused
- bucket: approved_firm_requests
initial: open
states:
open:
event: received
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Open'
body: |-
Hello {name},
We have received what you sent about To be approved by us and put on the list of firms that may file.
Solveig Hauge at byggesak@vestmark.example
checked:
event: checked
listed:
event: listed
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Listed'
body: |-
Hello {name},
What you sent about To be approved by us and put on the list of firms that may file is now on the list.
Solveig Hauge at byggesak@vestmark.example
grants: approved_firms
refused:
event: refused
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Refused'
body: |-
Hello {name},
What you sent about To be approved by us and put on the list of firms that may file is now refused.
Solveig Hauge at byggesak@vestmark.example
transitions:
checked:
- listed
- refused
open:
- checked
- refused
- bucket: completion_certificates
initial: open
states:
open:
event: received
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Open'
body: |-
Hello {name},
We have received what you sent about A completion certificate for the finished work.
Solveig Hauge at byggesak@vestmark.example
checked:
event: checked
issued:
event: issued
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Issued'
body: |-
Hello {name},
What you sent about A completion certificate for the finished work is now certificate signed.
Solveig Hauge at byggesak@vestmark.example
refused:
event: refused
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Refused'
body: |-
Hello {name},
What you sent about A completion certificate for the finished work is now refused.
Solveig Hauge at byggesak@vestmark.example
transitions:
checked:
- issued
- refused
open:
- checked
- refused
- bucket: exemptions
initial: open
states:
open:
event: received
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Open'
body: |-
Hello {name},
We have received what you sent about An exemption from the zoning rules, decided alongside their application.
Solveig Hauge at byggesak@vestmark.example
county_asked:
event: county_asked
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: County asked'
body: |-
Hello {name},
What you sent about An exemption from the zoning rules, decided alongside their application is now county asked.
Solveig Hauge at byggesak@vestmark.example
after:
days: 42
to: county_heard
county_heard:
event: county_heard
granted:
event: granted
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Granted'
body: |-
Hello {name},
What you sent about An exemption from the zoning rules, decided alongside their application is now granted.
Solveig Hauge at byggesak@vestmark.example
refused:
event: refused
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Refused'
body: |-
Hello {name},
What you sent about An exemption from the zoning rules, decided alongside their application is now refused.
Solveig Hauge at byggesak@vestmark.example
transitions:
county_asked:
- county_heard
- refused
county_heard:
- granted
- refused
open:
- county_asked
- refused
- bucket: hearing_answers
initial: open
states:
open:
event: received
after:
days: 42
to: no_answer
answered:
event: answered
no_answer:
event: no_answer
transitions:
open:
- answered
- no_answer
- bucket: illegal_building
initial: open
states:
open:
event: received
inspected:
event: inspected
owner_written_to:
event: owner_written_to
explained:
event: explained
fined:
event: fined
applied_for:
event: applied_for
taken_down:
event: taken_down
nothing_illegal:
event: nothing_illegal
transitions:
explained:
- fined
- applied_for
- taken_down
- nothing_illegal
fined:
- applied_for
- taken_down
inspected:
- owner_written_to
- nothing_illegal
open:
- inspected
- nothing_illegal
owner_written_to:
- explained
- bucket: inspections
initial: open
states:
open:
event: received
to_put_right:
event: to_put_right
as_approved:
event: as_approved
transitions:
open:
- to_put_right
- as_approved
to_put_right:
- as_approved
- bucket: objections
initial: open
states:
open:
event: received
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Open'
body: |-
Hello {name},
We have received what you sent about To object to an application and have the objection answered in the decision.
Solveig Hauge at byggesak@vestmark.example
registered:
event: registered
mail:
to: '{applications.email}'
subject: 'Vestmark kommune - Building and Planning: Registered'
body: |-
A case in objections is now registered on the case: .
Solveig Hauge at byggesak@vestmark.example
answered:
event: answered
addressed:
event: addressed
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Addressed'
body: |-
Hello {name},
What you sent about To object to an application and have the objection answered in the decision is now addressed in the decision.
Solveig Hauge at byggesak@vestmark.example
transitions:
answered:
- addressed
open:
- registered
registered:
- answered
- addressed
- bucket: paper_objections
initial: open
states:
open:
event: received
registered:
event: registered
answered:
event: answered
addressed:
event: addressed
transitions:
answered:
- addressed
open:
- registered
registered:
- answered
- addressed
- bucket: pre_application_meetings
initial: open
states:
open:
event: received
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Open'
body: |-
Hello {name},
We have received what you sent about A meeting with a case officer, and a written note of what we told them.
What you can do next: {site}/decide/pre-application-meeting?chain={chain}&email={email}
Solveig Hauge at byggesak@vestmark.example
scheduled:
event: scheduled
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Scheduled'
body: |-
Hello {name},
What you sent about A meeting with a case officer, and a written note of what we told them is now time found.
What you can do next: {site}/decide/pre-application-meeting?chain={chain}&email={email}
Solveig Hauge at byggesak@vestmark.example
met:
event: met
written_up:
event: written_up
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Written up'
body: |-
Hello {name},
What you sent about A meeting with a case officer, and a written note of what we told them is now written down and sent.
Solveig Hauge at byggesak@vestmark.example
cancelled:
event: cancelled
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Cancelled'
body: |-
Hello {name},
What you sent about A meeting with a case officer, and a written note of what we told them is now cancelled.
Solveig Hauge at byggesak@vestmark.example
transitions:
met:
- written_up
open:
- scheduled
- cancelled
scheduled:
- met
- cancelled
- bucket: temporary_permissions
initial: open
states:
open:
event: received
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Open'
body: |-
Hello {name},
We have received what you sent about A temporary permission to use the building.
Solveig Hauge at byggesak@vestmark.example
checked:
event: checked
issued:
event: issued
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Issued'
body: |-
Hello {name},
What you sent about A temporary permission to use the building is now temporary permission signed.
Solveig Hauge at byggesak@vestmark.example
refused:
event: refused
mail:
to: submitter
subject: 'Vestmark kommune - Building and Planning: Refused'
body: |-
Hello {name},
What you sent about A temporary permission to use the building is now refused.
Solveig Hauge at byggesak@vestmark.example
transitions:
checked:
- issued
- refused
open:
- checked
- refused
@@ -0,0 +1,504 @@
needs:
- id: pre-application-meeting
who: Anyone who wants to sit down with us before they spend money on drawings
wants: A meeting with a case officer, and a written note of what we told them
enters: /
via: Build
lands_in: pre_application_meetings
handled_by: case_officers
stages:
- open
- scheduled
- met
- written_up
- cancelled
done_when:
- written_up
- cancelled
success:
- written_up
max_steps: 2
max_fields: 4
stage_words:
open: asked for
scheduled: time found
met: meeting held
written_up: written down and sent
cancelled: cancelled
- id: application
who: A homeowner who wants a garage, an extension, a new window or another change to their property
wants: Permission to build, demolish, divide a property or change what a building is used for
enters: /
via: Build
lands_in: applications
handled_by: case_officers
stages:
- open
- papers_missing
- papers_received
- complete
- in_hearing
- hearing_over
- recommended
- approved
- approved_with_conditions
- refused
- withdrawn
done_when:
- approved
- approved_with_conditions
- refused
- withdrawn
success:
- approved
- approved_with_conditions
max_steps: 2
max_fields: 5
stage_words:
open: received
papers_missing: papers missing, clock stopped
papers_received: missing papers sent in
complete: complete, clock running
in_hearing: out to neighbours and agencies
hearing_over: hearing over
recommended: recommendation written
approved: approved
approved_with_conditions: approved with conditions
refused: refused
withdrawn: withdrawn
also_moved_by:
- head_of_section
- id: firm-application
who: An approved architect or engineering firm filing on behalf of an owner
wants: To file a building application for a client and see what is missing
enters: /approved_firms/firm-application
via: To file a building application for a client and see what is missing
lands_in: applications
handled_by: case_officers
stages:
- open
- papers_missing
- papers_received
- complete
- in_hearing
- hearing_over
- recommended
- approved
- approved_with_conditions
- refused
- withdrawn
done_when:
- approved
- approved_with_conditions
- refused
- withdrawn
success:
- approved
- approved_with_conditions
max_steps: 1
max_fields: 6
stage_words:
open: received
papers_missing: papers missing, clock stopped
papers_received: missing papers sent in
complete: complete, clock running
in_hearing: out to neighbours and agencies
hearing_over: hearing over
recommended: recommendation written
approved: approved
approved_with_conditions: approved with conditions
refused: refused
withdrawn: withdrawn
enters_as: approved_firms
also_moved_by:
- head_of_section
- id: exemption
who: An applicant whose plans break the zoning rules
wants: An exemption from the zoning rules, decided alongside their application
enters: /status/applications/[key]
via: An exemption from the zoning rules, decided alongside their application
lands_in: exemptions
handled_by: case_officers
stages:
- open
- county_asked
- county_heard
- granted
- refused
done_when:
- granted
- refused
success:
- granted
max_steps: 1
max_fields: 4
stage_words:
open: received
county_asked: county asked
county_heard: county has answered or its deadline has passed
granted: granted
refused: refused
also_moved_by:
- head_of_section
- id: objection
who: A neighbour who got a notice in the post and does not agree with what is planned next door
wants: To object to an application and have the objection answered in the decision
enters: /status/applications/[key]
via: To object to an application and have the objection answered in the decision
lands_in: objections
handled_by: case_officers
stages:
- open
- registered
- answered
- addressed
done_when:
- addressed
success:
- addressed
max_steps: 1
max_fields: 4
stage_words:
open: received
registered: registered on the case
answered: answered by the applicant
addressed: addressed in the decision
also_moved_by:
- approved_firms
- front_desk
- id: logged-objection
who: The front desk, when an objection comes in on paper or over the counter
wants: To put the objection on the right case straight away, instead of stapling it to a folder
enters: /front_desk/logged-objection
via: To put the objection on the right case straight away, instead of stapling it to a folder
lands_in: paper_objections
handled_by: case_officers
stages:
- open
- registered
- answered
- addressed
done_when:
- addressed
success:
- addressed
max_steps: 1
max_fields: 5
stage_words:
open: received
registered: registered on the case
answered: answered by the applicant
addressed: addressed in the decision
enters_as: front_desk
also_moved_by:
- approved_firms
- front_desk
- id: hearing-request
who: A case officer who is obliged to ask another authority about an application
wants: To ask the road authority, the fire service, the heritage office or the county, and go on when the deadline has passed
enters: /case_officers/hearing-request
via: To ask the road authority, the fire service, the heritage office or the county, and go on when the deadline has passed
lands_in: hearing_answers
handled_by: case_officers
stages:
- open
- answered
- no_answer
done_when:
- answered
- no_answer
success:
- answered
max_steps: 1
max_fields: 4
stage_words:
open: asked
answered: answered
no_answer: deadline passed without an answer
enters_as: case_officers
also_moved_by:
- agencies
- id: appeal
who: Anyone with an interest in a decision, the applicant or a neighbour
wants: To appeal a decision we have made
enters: /status/applications/[key]
via: To appeal a decision we have made
lands_in: appeals
handled_by: case_officers
stages:
- open
- under_review
- decision_changed
- sent_to_board
- upheld
- overturned
- dismissed
done_when:
- decision_changed
- upheld
- overturned
- dismissed
success:
- decision_changed
- upheld
- overturned
max_steps: 1
max_fields: 4
stage_words:
open: received
under_review: we are going through it ourselves
decision_changed: we changed our own decision
sent_to_board: sent to the appeals board
upheld: decision upheld by the board
overturned: decision overturned by the board
dismissed: dismissed
also_moved_by:
- appeals_board
- head_of_section
- id: illegal-building-report
who: Someone who sees something going up behind their fence without permission
wants: To tell us, so that we go and look
enters: /
via: To tell us, so that we go and look
lands_in: illegal_building
handled_by: case_officers
stages:
- open
- inspected
- owner_written_to
- explained
- fined
- applied_for
- taken_down
- nothing_illegal
done_when:
- applied_for
- taken_down
- nothing_illegal
success:
- applied_for
- taken_down
max_steps: 1
max_fields: 3
stage_words:
open: reported
inspected: we have been and looked
owner_written_to: owner written to
explained: owner has explained
fined: weekly fine running
applied_for: applied for properly
taken_down: taken down
nothing_illegal: nothing illegal found
also_moved_by:
- head_of_section
- inspectors
- id: logged-report
who: The front desk, when someone rings or comes in about building without permission
wants: To log the report so an inspector goes and looks
enters: /front_desk/logged-report
via: To log the report so an inspector goes and looks
lands_in: illegal_building
handled_by: case_officers
stages:
- open
- inspected
- owner_written_to
- explained
- fined
- applied_for
- taken_down
- nothing_illegal
done_when:
- applied_for
- taken_down
- nothing_illegal
success:
- applied_for
- taken_down
max_steps: 1
max_fields: 3
stage_words:
open: reported
inspected: we have been and looked
owner_written_to: owner written to
explained: owner has explained
fined: weekly fine running
applied_for: applied for properly
taken_down: taken down
nothing_illegal: nothing illegal found
enters_as: front_desk
also_moved_by:
- head_of_section
- inspectors
- id: inspection
who: An inspector on site, writing on a phone in a cold wind
wants: To write up what was found on a case and set a date for what must be put right
enters: /inspectors/inspection
via: To write up what was found on a case and set a date for what must be put right
lands_in: inspections
handled_by: inspectors
stages:
- open
- to_put_right
- as_approved
done_when:
- as_approved
success:
- as_approved
max_steps: 1
max_fields: 3
stage_words:
open: inspected
to_put_right: to be put right, then we go back
as_approved: as approved
enters_as: inspectors
- id: completion-certificate
who: An approved firm whose work on a case is done
wants: A completion certificate for the finished work
enters: /approved_firms/completion-certificate
via: A completion certificate for the finished work
lands_in: completion_certificates
handled_by: case_officers
stages:
- open
- checked
- issued
- refused
done_when:
- issued
- refused
success:
- issued
max_steps: 1
max_fields: 5
stage_words:
open: asked for
checked: inspections and outstanding work checked
issued: certificate signed
refused: refused
enters_as: approved_firms
also_moved_by:
- head_of_section
- id: temporary-permission
who: An approved firm whose client wants to move in before everything is done
wants: A temporary permission to use the building
enters: /approved_firms/temporary-permission
via: A temporary permission to use the building
lands_in: temporary_permissions
handled_by: case_officers
stages:
- open
- checked
- issued
- refused
done_when:
- issued
- refused
success:
- issued
max_steps: 1
max_fields: 6
stage_words:
open: asked for
checked: inspections and outstanding work checked
issued: temporary permission signed
refused: refused
enters_as: approved_firms
also_moved_by:
- head_of_section
- id: firm-approval
who: An architect or engineering firm that wants to file applications for owners
wants: To be approved by us and put on the list of firms that may file
enters: /
via: Firm
lands_in: approved_firm_requests
handled_by: case_officers
stages:
- open
- checked
- listed
- refused
done_when:
- listed
- refused
success:
- listed
max_steps: 2
max_fields: 6
stage_words:
open: received
checked: registration, insurance and qualifications checked
listed: on the list
refused: refused
also_moved_by:
- head_of_section
personas:
- id: garage-owner
need: pre-application-meeting
text: We want to put a double garage where the old shed is. Before I pay an architect I'd like to know whether you'll even allow it, because the neighbour says it's too close to the road.
- id: shop-to-flats
need: pre-application-meeting
text: I own the old grocery on Torget and want to make four flats out of it. There are a lot of questions - parking, fire, the facade is listed. Can we sit down with someone?
- id: firm-files-extension
need: firm-application
text: We are the responsible applicant for an extension at Bjorkeveien 14. Drawings, site plan and the neighbour notices are all ready. We file maybe forty of these a year.
- id: owner-small-window
need: application
text: I want to put a dormer window in my roof. The man at the counter said I have to apply even though it's small.
- id: missing-drawings
need: firm-application
text: You wrote that our section drawing is missing and the case is on hold. I've got it here now, where do I send it so the clock starts again?
- id: too-close-to-boundary
need: exemption
text: The garage ends up one and a half metres from the boundary and the plan says four. We are asking you to allow it anyway - the ground falls away steeply everywhere else on the plot.
- id: neighbour-view
need: objection
text: I got a notice about the extension at number 14. It takes the afternoon sun off my entire terrace and I want that on the record before you decide anything.
- id: neighbour-parking
need: objection
text: The flats they want to build in the old grocery have four parking places for four flats and everyone here already parks on the street. I object.
- id: road-authority
need: hearing-request
text: 'Regarding your case 2026/418: the access onto the county road is within the sight line and we cannot accept it as drawn. Our formal reply is attached.'
- id: fire-service
need: hearing-request
text: We have looked at the conversion on Torget. We have no objection provided the stairwell is upgraded. Reference your case 2026/501.
- id: refused-applicant
need: appeal
text: You refused our exemption on the ninth. We don't accept the reasoning - you've allowed the same thing twice in the same street. We're appealing.
- id: neighbour-appeals
need: appeal
text: You approved the extension next door even though I objected. I'm appealing the decision. What do I need to send?
- id: board-member
need: appeal
text: I sit on the appeals board. I need the case, our own decision, and what the neighbours wrote, before Tuesday.
- id: inspector-on-roof
need: inspection
text: I'm up on the scaffold at Bjorkeveien. The fire wall isn't built to the drawing at all. I've got gloves on and it's blowing. I want this logged before I climb down.
- id: inspector-all-good
need: inspection
text: Been out at Torget. Everything is as approved. Nothing to report but I have to record that I was there.
- id: firm-wants-certificate
need: completion-certificate
text: The work at Bjorkeveien 14 is finished and inspected. We're asking for the completion certificate so the owners can get their mortgage released.
- id: wants-to-move-in
need: temporary-permission
text: The house is done apart from the outside steps, which we can't pour until spring. The family has sold their flat. Can we get a temporary permission to move in?
- id: something-behind-fence
need: illegal-building-report
text: There's a large structure going up behind the fence at Solbakken 7. Nobody has had a notice about it and it's been going on for two weeks.
- id: owner-explains
need: illegal-building-report
text: I got your letter about the terrace. I genuinely did not know it needed an application, it's been there since we moved in. What happens now?
- id: new-firm
need: firm-approval
text: We are a three-person architecture firm that has just started. We want to be approved so we can file applications for our clients in your municipality.
- id: firm-insurance-lapsed
need: firm-approval
text: You wrote that our liability insurance certificate has expired. We have renewed it, here it is.
- id: counter-phone-call
need: log-counter-enquiry
text: A woman rang about the case behind her house. Wants to know where it stands. I'm at the counter and there's a queue - I need to write it down and send it to whoever has that case.
- id: where-is-my-case
need: case-status-enquiry
text: I sent in my application five weeks ago and I've heard nothing. Is anyone looking at it? Is it in the six weeks with the neighbours or is it waiting on me?
@@ -0,0 +1 @@
qualifies: agencies
@@ -0,0 +1,62 @@
name: What needs doing?
description: Everything agencies looks after.
responsible:
name: Solveig Hauge
contact: byggesak@vestmark.example
alternatives:
- name: Hearing answers
description: Sent in by A case officer who is obliged to ask another authority about an application.
action: /agencies
consequence:
- Confirm
features:
- name: Hearing answers
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: hearing_answers
requires_group: agencies
transitions:
- from: open
to: answered
label: Answered
- name: Invite someone into Agencies
description: They get an account, a place in Agencies, and a one-time link to set their own password or passkey.
action: /agencies
consequence:
- Invite
invite:
group: agencies
features:
- name: Who
description: Their name, and the address the account and its one-time link go to.
requirements:
- name: name
label: Name
- name: email
label: Email
type: email
- name: Invitations sent
description: Each invite and where it stands. A link that runs out unused can be sent again.
action: /agencies
consequence:
- Confirm
features:
- name: Who has been invited
description: Each row is one invitation. It is done by itself when the person signs in, and expired when the link ran out unused.
resource:
source:
kind: kv
bucket: portal_invites
requires_group: agencies
transitions:
- from: open
to: done
label: Is in
- from: expired
to: open
label: Send again
- from: expired
to: done
label: Is in
@@ -0,0 +1 @@
qualifies: appeals_board
@@ -0,0 +1,65 @@
name: What needs doing?
description: Everything appeals board looks after.
responsible:
name: Solveig Hauge
contact: byggesak@vestmark.example
alternatives:
- name: Appeals
description: Sent in by Anyone with an interest in a decision, the applicant or a neighbour.
action: /appeals_board
consequence:
- Confirm
features:
- name: Appeals
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: appeals
requires_group: appeals_board
transitions:
- from: sent_to_board
to: upheld
label: Decision upheld by the board
- from: sent_to_board
to: overturned
label: Decision overturned by the board
- name: Invite someone into Appeals board
description: They get an account, a place in Appeals board, and a one-time link to set their own password or passkey.
action: /appeals_board
consequence:
- Invite
invite:
group: appeals_board
features:
- name: Who
description: Their name, and the address the account and its one-time link go to.
requirements:
- name: name
label: Name
- name: email
label: Email
type: email
- name: Invitations sent
description: Each invite and where it stands. A link that runs out unused can be sent again.
action: /appeals_board
consequence:
- Confirm
features:
- name: Who has been invited
description: Each row is one invitation. It is done by itself when the person signs in, and expired when the link ran out unused.
resource:
source:
kind: kv
bucket: portal_invites
requires_group: appeals_board
transitions:
- from: open
to: done
label: Is in
- from: expired
to: open
label: Send again
- from: expired
to: done
label: Is in
@@ -0,0 +1 @@
qualifies: approved_firms
@@ -0,0 +1,5 @@
name: What happens now?
description: It has reached our case officers.
alternatives:
- name: We read it and come back to you
description: Questions in the meantime go to Solveig Hauge at byggesak@vestmark.example.
@@ -0,0 +1,47 @@
followup: false
name: Completion certificate?
description: ''
responsible:
name: Solveig Hauge
contact: byggesak@vestmark.example
alternatives:
- name: A completion certificate for the finished work
description: For An approved firm whose work on a case is done.
action: /approved_firms/completion-certificate-sent
consequence:
- Send
record_as: completion_certificates
features:
- name: What you need
description: Your firm must be on our list of approved firms, and the application must be approved; have its reference ready.
icon: lucide:key
- name: What happens next
description: It is asked for, then inspections and outstanding work checked, and ends certificate signed or refused.
icon: lucide:route
- name: Who reads it
description: Case officers. Questions go to Solveig Hauge at byggesak@vestmark.example.
icon: lucide:users
- name: Details
requirements:
- name: name
label: Name
type: text
value: '{user.name}'
- name: email
label: Email
type: email
value: '{user.email}'
- name: application_reference
label: Application reference
type: text
- name: finished_on
label: Finished on
type: date
- name: what_was_built
label: What was built
type: textarea
optional: true
- name: still_outstanding
label: Still outstanding
type: textarea
optional: true
@@ -0,0 +1,10 @@
name: What happens now?
description: It has reached our case officers.
alternatives:
- name: We read it and come back to you
description: Questions in the meantime go to Solveig Hauge at byggesak@vestmark.example.
- name: See all applications
description: ''
action: /status/applications
consequence:
- Open
@@ -0,0 +1,73 @@
followup: false
name: Firm application?
description: ''
responsible:
name: Solveig Hauge
contact: byggesak@vestmark.example
alternatives:
- name: To file a building application for a client and see what is missing
description: For An approved architect or engineering firm filing on behalf of an owner.
action: /approved_firms/firm-application-sent
consequence:
- Send
record_as: applications
features:
- name: What you need
description: Your firm must be on our list of approved firms before it may file anything.
icon: lucide:key
- name: What happens next
description: It is received, then papers missing, clock stopped, then missing papers sent in, then complete, clock running, then out to neighbours and agencies, then hearing over, then recommendation written, and ends approved, approved with conditions, refused or withdrawn.
icon: lucide:route
- name: Who reads it
description: Case officers. Questions go to Solveig Hauge at byggesak@vestmark.example.
icon: lucide:users
- name: Details
requirements:
- name: name
label: Name
type: text
value: '{user.name}'
- name: email
label: Email
type: email
value: '{user.email}'
- name: property_address
label: Property address
type: text
- name: kind_of_work
label: Kind of work
type: select
options:
- New building
- Extension
- Garage or outbuilding
- Window or facade change
- Demolition
- Dividing a property
- Change of use
- name: what_you_want_to_do
label: What you want to do
type: textarea
- name: enclosed
label: Enclosed
type: select
options:
- Site plan
- Floor plans
- Elevations
- Section drawing
- Neighbour notices sent
- Statement from the owner
multiple: true
- name: owner_name
label: Owner name
type: text
optional: true
- name: phone
label: Phone
type: tel
optional: true
- name: place
label: Place
type: location
optional: true
@@ -0,0 +1,55 @@
name: What needs doing?
description: Everything approved firms looks after.
responsible:
name: Solveig Hauge
contact: byggesak@vestmark.example
alternatives:
- name: Objections
description: Sent in by A neighbour who got a notice in the post and does not agree with what is planned next door.
action: /approved_firms
consequence:
- Confirm
features:
- name: Objections
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: objections
requires_group: approved_firms
transitions:
- from: registered
to: answered
label: Answered by the applicant
- name: Paper objections
description: Sent in by The front desk, when an objection comes in on paper or over the counter.
action: /approved_firms
consequence:
- Confirm
features:
- name: Paper objections
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: paper_objections
requires_group: approved_firms
transitions:
- from: registered
to: answered
label: Answered by the applicant
- name: To file a building application for a client and see what is missing
description: For An approved architect or engineering firm filing on behalf of an owner.
action: /approved_firms/firm-application
consequence:
- Open
- name: A completion certificate for the finished work
description: For An approved firm whose work on a case is done.
action: /approved_firms/completion-certificate
consequence:
- Open
- name: A temporary permission to use the building
description: For An approved firm whose client wants to move in before everything is done.
action: /approved_firms/temporary-permission
consequence:
- Open
@@ -0,0 +1,5 @@
name: What happens now?
description: It has reached our case officers.
alternatives:
- name: We read it and come back to you
description: Questions in the meantime go to Solveig Hauge at byggesak@vestmark.example.
@@ -0,0 +1,46 @@
followup: false
name: Temporary permission?
description: ''
responsible:
name: Solveig Hauge
contact: byggesak@vestmark.example
alternatives:
- name: A temporary permission to use the building
description: For An approved firm whose client wants to move in before everything is done.
action: /approved_firms/temporary-permission-sent
consequence:
- Send
record_as: temporary_permissions
features:
- name: What you need
description: Your firm must be on our list of approved firms, and the application must be approved; have its reference ready.
icon: lucide:key
- name: What happens next
description: It is asked for, then inspections and outstanding work checked, and ends temporary permission signed or refused.
icon: lucide:route
- name: Who reads it
description: Case officers. Questions go to Solveig Hauge at byggesak@vestmark.example.
icon: lucide:users
- name: Details
requirements:
- name: name
label: Name
type: text
value: '{user.name}'
- name: email
label: Email
type: email
value: '{user.email}'
- name: application_reference
label: Application reference
type: text
- name: move_in_on
label: Move in on
type: date
- name: still_outstanding
label: Still outstanding
type: textarea
- name: finished_by
label: Finished by
type: date
optional: true
@@ -0,0 +1,99 @@
name: What do you need?
description: For You want to build, demolish, divide a property or change what a building is used for.
responsible:
name: Solveig Hauge
contact: byggesak@vestmark.example
alternatives:
- name: A meeting with a case officer, and a written note of what we told them
description: For Anyone who wants to sit down with us before they spend money on drawings.
action: /received/pre-application-meeting
consequence:
- Send
record_as: pre_application_meetings
features:
- name: What happens next
description: It is asked for, then time found, then meeting held, and ends written down and sent or cancelled.
icon: lucide:route
- name: Who reads it
description: Case officers. Questions go to Solveig Hauge at byggesak@vestmark.example.
icon: lucide:users
- name: Details
requirements:
- name: name
label: Name
type: text
- name: email
label: Email
type: email
- name: property_address
label: Property address
type: text
- name: what_you_plan
label: What you plan
type: textarea
- name: phone
label: Phone
type: tel
optional: true
- name: place
label: Place
type: location
optional: true
- name: Permission to build, demolish, divide a property or change what a building is used for
description: For A homeowner who wants a garage, an extension, a new window or another change to their property.
action: /received/application
consequence:
- Send
record_as: applications
features:
- name: What happens next
description: It is received, then papers missing, clock stopped, then missing papers sent in, then complete, clock running, then out to neighbours and agencies, then hearing over, then recommendation written, and ends approved, approved with conditions, refused or withdrawn.
icon: lucide:route
- name: Who reads it
description: Case officers. Questions go to Solveig Hauge at byggesak@vestmark.example.
icon: lucide:users
- name: Details
requirements:
- name: name
label: Name
type: text
- name: email
label: Email
type: email
- name: property_address
label: Property address
type: text
- name: kind_of_work
label: Kind of work
type: select
options:
- New building
- Extension
- Garage or outbuilding
- Window or facade change
- Demolition
- Dividing a property
- Change of use
- name: what_you_want_to_do
label: What you want to do
type: textarea
- name: enclosed
label: Enclosed
type: select
optional: true
options:
- Site plan
- Floor plans
- Elevations
- Section drawing
- Neighbour notices sent
- Statement from the owner
multiple: true
- name: phone
label: Phone
type: tel
optional: true
- name: place
label: Place
type: location
optional: true
@@ -0,0 +1 @@
qualifies: case_officers
@@ -0,0 +1,5 @@
name: What happens now?
description: It has reached our case officers.
alternatives:
- name: We read it and come back to you
description: Questions in the meantime go to Solveig Hauge at byggesak@vestmark.example.
@@ -0,0 +1,40 @@
followup: false
name: Hearing request?
description: ''
responsible:
name: Solveig Hauge
contact: byggesak@vestmark.example
alternatives:
- name: To ask the road authority, the fire service, the heritage office or the county, and go on when the deadline has passed
description: For A case officer who is obliged to ask another authority about an application.
action: /case_officers/hearing-request-sent
consequence:
- Send
record_as: hearing_answers
features:
- name: What happens next
description: It is asked, and ends answered or deadline passed without an answer.
icon: lucide:route
- name: Who reads it
description: Case officers. Questions go to Solveig Hauge at byggesak@vestmark.example.
icon: lucide:users
- name: Details
requirements:
- name: application_reference
label: Application reference
type: text
- name: agency
label: Agency
type: select
options:
- Road authority
- Fire service
- Heritage office
- County
- name: what_we_ask
label: What we ask
type: textarea
- name: answer_by
label: Answer by
type: date
optional: true
@@ -0,0 +1,368 @@
name: What needs doing?
description: Everything case officers looks after.
responsible:
name: Solveig Hauge
contact: byggesak@vestmark.example
alternatives:
- name: Appeals
description: Sent in by Anyone with an interest in a decision, the applicant or a neighbour.
action: /case_officers
consequence:
- Confirm
features:
- name: Appeals
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: appeals
requires_group: case_officers
transitions:
- from: open
to: under_review
label: We are going through it ourselves
- from: open
to: dismissed
label: Dismissed
- from: under_review
to: sent_to_board
label: Sent to the appeals board
- from: under_review
to: dismissed
label: Dismissed
- name: Applications
description: Sent in by A homeowner who wants a garage, an extension, a new window or another change to their property or An approved architect or engineering firm filing on behalf of an owner.
action: /case_officers
consequence:
- Confirm
features:
- name: Applications
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: applications
requires_group: case_officers
transitions:
- from: complete
to: in_hearing
label: Out to neighbours and agencies
- from: complete
to: withdrawn
label: Withdrawn
- from: complete
to: papers_missing
label: Papers missing, clock stopped
- from: hearing_over
to: recommended
label: Recommendation written
- from: hearing_over
to: withdrawn
label: Withdrawn
- from: in_hearing
to: hearing_over
label: Hearing over
- from: in_hearing
to: withdrawn
label: Withdrawn
- from: in_hearing
to: papers_missing
label: Papers missing, clock stopped
- from: open
to: complete
label: Complete, clock running
- from: open
to: withdrawn
label: Withdrawn
- from: open
to: papers_missing
label: Papers missing, clock stopped
- from: papers_missing
to: complete
label: Complete, clock running
- from: papers_missing
to: withdrawn
label: Withdrawn
- from: papers_received
to: complete
label: Complete, clock running
- from: papers_received
to: withdrawn
label: Withdrawn
- from: papers_received
to: papers_missing
label: Papers missing, clock stopped
- from: recommended
to: withdrawn
label: Withdrawn
- name: Approved firm requests
description: Sent in by An architect or engineering firm that wants to file applications for owners.
action: /case_officers
consequence:
- Confirm
features:
- name: Approved firm requests
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: approved_firm_requests
requires_group: case_officers
transitions:
- from: open
to: checked
label: Registration, insurance and qualifications checked
- name: Completion certificates
description: Sent in by An approved firm whose work on a case is done.
action: /case_officers
consequence:
- Confirm
features:
- name: Completion certificates
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: completion_certificates
requires_group: case_officers
transitions:
- from: open
to: checked
label: Inspections and outstanding work checked
- name: Exemptions
description: Sent in by An applicant whose plans break the zoning rules.
action: /case_officers
consequence:
- Confirm
features:
- name: Exemptions
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: exemptions
requires_group: case_officers
transitions:
- from: county_asked
to: county_heard
label: County has answered or its deadline has passed
- from: open
to: county_asked
label: County asked
- name: Hearing answers
description: Sent in by A case officer who is obliged to ask another authority about an application.
action: /case_officers
consequence:
- Confirm
features:
- name: Hearing answers
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: hearing_answers
requires_group: case_officers
transitions:
- from: open
to: answered
label: Answered
- from: open
to: no_answer
label: Deadline passed without an answer
- name: Illegal building
description: Sent in by Someone who sees something going up behind their fence without permission or The front desk, when someone rings or comes in about building without permission.
action: /case_officers
consequence:
- Confirm
features:
- name: Illegal building
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: illegal_building
requires_group: case_officers
transitions:
- from: explained
to: applied_for
label: Applied for properly
- from: explained
to: taken_down
label: Taken down
- from: explained
to: nothing_illegal
label: Nothing illegal found
- from: fined
to: applied_for
label: Applied for properly
- from: fined
to: taken_down
label: Taken down
- from: inspected
to: owner_written_to
label: Owner written to
- from: inspected
to: nothing_illegal
label: Nothing illegal found
- from: open
to: nothing_illegal
label: Nothing illegal found
- from: owner_written_to
to: explained
label: Owner has explained
- name: Inspections
description: Sent in by An inspector on site, writing on a phone in a cold wind.
action: /case_officers
consequence:
- Confirm
features:
- name: Inspections
description: Each row is one case and the stage it has reached. Another desk moves these.
resource:
source:
kind: kv
bucket: inspections
requires_group: case_officers
transitions: []
- name: Objections
description: Sent in by A neighbour who got a notice in the post and does not agree with what is planned next door.
action: /case_officers
consequence:
- Confirm
features:
- name: Objections
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: objections
requires_group: case_officers
transitions:
- from: answered
to: addressed
label: Addressed in the decision
- from: open
to: registered
label: Registered on the case
- from: registered
to: answered
label: Answered by the applicant
- from: registered
to: addressed
label: Addressed in the decision
- name: Paper objections
description: Sent in by The front desk, when an objection comes in on paper or over the counter.
action: /case_officers
consequence:
- Confirm
features:
- name: Paper objections
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: paper_objections
requires_group: case_officers
transitions:
- from: answered
to: addressed
label: Addressed in the decision
- from: open
to: registered
label: Registered on the case
- from: registered
to: answered
label: Answered by the applicant
- from: registered
to: addressed
label: Addressed in the decision
- name: Pre application meetings
description: Sent in by Anyone who wants to sit down with us before they spend money on drawings.
action: /case_officers
consequence:
- Confirm
features:
- name: Pre application meetings
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: pre_application_meetings
requires_group: case_officers
transitions:
- from: met
to: written_up
label: Written down and sent
- from: open
to: scheduled
label: Time found
- from: open
to: cancelled
label: Cancelled
- from: scheduled
to: met
label: Meeting held
- from: scheduled
to: cancelled
label: Cancelled
- name: Temporary permissions
description: Sent in by An approved firm whose client wants to move in before everything is done.
action: /case_officers
consequence:
- Confirm
features:
- name: Temporary permissions
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: temporary_permissions
requires_group: case_officers
transitions:
- from: open
to: checked
label: Inspections and outstanding work checked
- name: To ask the road authority, the fire service, the heritage office or the county, and go on when the deadline has passed
description: For A case officer who is obliged to ask another authority about an application.
action: /case_officers/hearing-request
consequence:
- Open
- name: Invite someone into Case officers
description: They get an account, a place in Case officers, and a one-time link to set their own password or passkey.
action: /case_officers
consequence:
- Invite
invite:
group: case_officers
features:
- name: Who
description: Their name, and the address the account and its one-time link go to.
requirements:
- name: name
label: Name
- name: email
label: Email
type: email
- name: Invitations sent
description: Each invite and where it stands. A link that runs out unused can be sent again.
action: /case_officers
consequence:
- Confirm
features:
- name: Who has been invited
description: Each row is one invitation. It is done by itself when the person signs in, and expired when the link ran out unused.
resource:
source:
kind: kv
bucket: portal_invites
requires_group: case_officers
transitions:
- from: open
to: done
label: Is in
- from: expired
to: open
label: Send again
- from: expired
to: done
label: Is in
@@ -0,0 +1,26 @@
name: What would you like to do?
description: ''
alternatives:
- name: Papers received
description: ''
self_transition:
bucket: applications
to: papers_received
from:
- open
- papers_missing
label: Papers received
- name: Withdrawn
description: ''
self_transition:
bucket: applications
to: withdrawn
from:
- complete
- hearing_over
- in_hearing
- open
- papers_missing
- papers_received
- recommended
label: Withdrawn
@@ -0,0 +1,26 @@
name: What would you like to do?
description: ''
alternatives:
- name: Papers received
description: ''
self_transition:
bucket: applications
to: papers_received
from:
- open
- papers_missing
label: Papers received
- name: Withdrawn
description: ''
self_transition:
bucket: applications
to: withdrawn
from:
- complete
- hearing_over
- in_hearing
- open
- papers_missing
- papers_received
- recommended
label: Withdrawn
@@ -0,0 +1,12 @@
name: What would you like to do?
description: ''
alternatives:
- name: Cancelled
description: ''
self_transition:
bucket: pre_application_meetings
to: cancelled
from:
- open
- scheduled
label: Cancelled
@@ -0,0 +1,67 @@
name: What do you need?
description: For You are an architect or an engineering firm filing on behalf of owners.
responsible:
name: Solveig Hauge
contact: byggesak@vestmark.example
alternatives:
- name: To file a building application for a client and see what is missing
description: For An approved architect or engineering firm filing on behalf of an owner.
action: /approved_firms/firm-application
consequence:
- Send
- name: A completion certificate for the finished work
description: For An approved firm whose work on a case is done.
action: /approved_firms/completion-certificate
consequence:
- Send
- name: A temporary permission to use the building
description: For An approved firm whose client wants to move in before everything is done.
action: /approved_firms/temporary-permission
consequence:
- Send
- name: To be approved by us and put on the list of firms that may file
description: For An architect or engineering firm that wants to file applications for owners.
action: /received/firm-approval
consequence:
- Send
record_as: approved_firm_requests
features:
- name: What happens next
description: It is received, then registration, insurance and qualifications checked, and ends on the list or refused.
icon: lucide:route
- name: Who reads it
description: Case officers. Questions go to Solveig Hauge at byggesak@vestmark.example.
icon: lucide:users
- name: Details
requirements:
- name: firm
label: Firm
type: text
- name: name
label: Name
type: text
- name: email
label: Email
type: email
- name: registration_number
label: Registration number
type: text
- name: insurance
label: Insurance
type: text
- name: qualified_for
label: Qualified for
type: select
options:
- Applying on behalf of owners
- Architectural design
- Structural engineering
- Fire safety design
- Geotechnical engineering
- Carrying out the work
- Independent control
multiple: true
- name: phone
label: Phone
type: tel
optional: true
@@ -0,0 +1 @@
qualifies: front_desk
@@ -0,0 +1,215 @@
name: What needs doing?
description: Everything front desk looks after.
responsible:
name: Solveig Hauge
contact: byggesak@vestmark.example
alternatives:
- name: Appeals
description: Sent in by Anyone with an interest in a decision, the applicant or a neighbour.
action: /front_desk
consequence:
- Confirm
features:
- name: Appeals
description: Each row is one case and the stage it has reached. Another desk moves these.
resource:
source:
kind: kv
bucket: appeals
requires_group: front_desk
transitions: []
- name: Applications
description: Sent in by A homeowner who wants a garage, an extension, a new window or another change to their property or An approved architect or engineering firm filing on behalf of an owner.
action: /front_desk
consequence:
- Confirm
features:
- name: Applications
description: Each row is one case and the stage it has reached. Another desk moves these.
resource:
source:
kind: kv
bucket: applications
requires_group: front_desk
transitions: []
- name: Approved firm requests
description: Sent in by An architect or engineering firm that wants to file applications for owners.
action: /front_desk
consequence:
- Confirm
features:
- name: Approved firm requests
description: Each row is one case and the stage it has reached. Another desk moves these.
resource:
source:
kind: kv
bucket: approved_firm_requests
requires_group: front_desk
transitions: []
- name: Completion certificates
description: Sent in by An approved firm whose work on a case is done.
action: /front_desk
consequence:
- Confirm
features:
- name: Completion certificates
description: Each row is one case and the stage it has reached. Another desk moves these.
resource:
source:
kind: kv
bucket: completion_certificates
requires_group: front_desk
transitions: []
- name: Exemptions
description: Sent in by An applicant whose plans break the zoning rules.
action: /front_desk
consequence:
- Confirm
features:
- name: Exemptions
description: Each row is one case and the stage it has reached. Another desk moves these.
resource:
source:
kind: kv
bucket: exemptions
requires_group: front_desk
transitions: []
- name: Hearing answers
description: Sent in by A case officer who is obliged to ask another authority about an application.
action: /front_desk
consequence:
- Confirm
features:
- name: Hearing answers
description: Each row is one case and the stage it has reached. Another desk moves these.
resource:
source:
kind: kv
bucket: hearing_answers
requires_group: front_desk
transitions: []
- name: Illegal building
description: Sent in by Someone who sees something going up behind their fence without permission or The front desk, when someone rings or comes in about building without permission.
action: /front_desk
consequence:
- Confirm
features:
- name: Illegal building
description: Each row is one case and the stage it has reached. Another desk moves these.
resource:
source:
kind: kv
bucket: illegal_building
requires_group: front_desk
transitions: []
- name: Objections
description: Sent in by A neighbour who got a notice in the post and does not agree with what is planned next door.
action: /front_desk
consequence:
- Confirm
features:
- name: Objections
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: objections
requires_group: front_desk
transitions:
- from: open
to: registered
label: Registered on the case
- name: Paper objections
description: Sent in by The front desk, when an objection comes in on paper or over the counter.
action: /front_desk
consequence:
- Confirm
features:
- name: Paper objections
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: paper_objections
requires_group: front_desk
transitions:
- from: open
to: registered
label: Registered on the case
- name: Pre application meetings
description: Sent in by Anyone who wants to sit down with us before they spend money on drawings.
action: /front_desk
consequence:
- Confirm
features:
- name: Pre application meetings
description: Each row is one case and the stage it has reached. Another desk moves these.
resource:
source:
kind: kv
bucket: pre_application_meetings
requires_group: front_desk
transitions: []
- name: Temporary permissions
description: Sent in by An approved firm whose client wants to move in before everything is done.
action: /front_desk
consequence:
- Confirm
features:
- name: Temporary permissions
description: Each row is one case and the stage it has reached. Another desk moves these.
resource:
source:
kind: kv
bucket: temporary_permissions
requires_group: front_desk
transitions: []
- name: To put the objection on the right case straight away, instead of stapling it to a folder
description: For The front desk, when an objection comes in on paper or over the counter.
action: /front_desk/logged-objection
consequence:
- Open
- name: To log the report so an inspector goes and looks
description: For The front desk, when someone rings or comes in about building without permission.
action: /front_desk/logged-report
consequence:
- Open
- name: Invite someone into Front desk
description: They get an account, a place in Front desk, and a one-time link to set their own password or passkey.
action: /front_desk
consequence:
- Invite
invite:
group: front_desk
features:
- name: Who
description: Their name, and the address the account and its one-time link go to.
requirements:
- name: name
label: Name
- name: email
label: Email
type: email
- name: Invitations sent
description: Each invite and where it stands. A link that runs out unused can be sent again.
action: /front_desk
consequence:
- Confirm
features:
- name: Who has been invited
description: Each row is one invitation. It is done by itself when the person signs in, and expired when the link ran out unused.
resource:
source:
kind: kv
bucket: portal_invites
requires_group: front_desk
transitions:
- from: open
to: done
label: Is in
- from: expired
to: open
label: Send again
- from: expired
to: done
label: Is in
@@ -0,0 +1,5 @@
name: What happens now?
description: It has reached our case officers.
alternatives:
- name: We read it and come back to you
description: Questions in the meantime go to Solveig Hauge at byggesak@vestmark.example.
@@ -0,0 +1,43 @@
followup: false
name: Logged objection?
description: ''
responsible:
name: Solveig Hauge
contact: byggesak@vestmark.example
alternatives:
- name: To put the objection on the right case straight away, instead of stapling it to a folder
description: For The front desk, when an objection comes in on paper or over the counter.
action: /front_desk/logged-objection-sent
consequence:
- Send
record_as: paper_objections
features:
- name: What happens next
description: It is received, then registered on the case, then answered by the applicant, and ends addressed in the decision.
icon: lucide:route
- name: Who reads it
description: Case officers. Questions go to Solveig Hauge at byggesak@vestmark.example.
icon: lucide:users
- name: Details
requirements:
- name: application_reference
label: Application reference
type: text
- name: name
label: Name
type: text
value: '{user.name}'
- name: objection
label: Objection
type: textarea
- name: received_on
label: Received on
type: date
- name: your_property
label: Your property
type: text
optional: true
- name: phone
label: Phone
type: tel
optional: true
@@ -0,0 +1,5 @@
name: What happens now?
description: It has reached our case officers.
alternatives:
- name: We read it and come back to you
description: Questions in the meantime go to Solveig Hauge at byggesak@vestmark.example.
@@ -0,0 +1,41 @@
followup: false
name: Logged report?
description: ''
responsible:
name: Solveig Hauge
contact: byggesak@vestmark.example
alternatives:
- name: To log the report so an inspector goes and looks
description: For The front desk, when someone rings or comes in about building without permission.
action: /front_desk/logged-report-sent
consequence:
- Send
record_as: illegal_building
features:
- name: What happens next
description: It is reported, then we have been and looked, then owner written to, then owner has explained, then weekly fine running, and ends applied for properly, taken down or nothing illegal found.
icon: lucide:route
- name: Who reads it
description: Case officers. Questions go to Solveig Hauge at byggesak@vestmark.example.
icon: lucide:users
- name: Details
requirements:
- name: where
label: Where
type: text
- name: what_is_being_built
label: What is being built
type: textarea
- name: place
label: Place
type: location
optional: true
- name: name
label: Name
type: text
optional: true
value: '{user.name}'
- name: phone
label: Phone
type: tel
optional: true
@@ -0,0 +1 @@
qualifies: head_of_section
@@ -0,0 +1,364 @@
name: What needs doing?
description: Everything head of section looks after.
responsible:
name: Solveig Hauge
contact: byggesak@vestmark.example
alternatives:
- name: Appeals
description: Sent in by Anyone with an interest in a decision, the applicant or a neighbour.
action: /head_of_section
consequence:
- Confirm
features:
- name: Appeals
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: appeals
requires_group: head_of_section
transitions:
- from: under_review
to: decision_changed
label: We changed our own decision
- name: Applications
description: Sent in by A homeowner who wants a garage, an extension, a new window or another change to their property or An approved architect or engineering firm filing on behalf of an owner.
action: /head_of_section
consequence:
- Confirm
features:
- name: Applications
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: applications
requires_group: head_of_section
transitions:
- from: recommended
to: approved
label: Approved
- from: recommended
to: approved_with_conditions
label: Approved with conditions
- from: recommended
to: refused
label: Refused
- name: Approved firm requests
description: Sent in by An architect or engineering firm that wants to file applications for owners.
action: /head_of_section
consequence:
- Confirm
features:
- name: Approved firm requests
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: approved_firm_requests
requires_group: head_of_section
transitions:
- from: checked
to: listed
label: On the list
- from: checked
to: refused
label: Refused
- from: open
to: refused
label: Refused
- name: Completion certificates
description: Sent in by An approved firm whose work on a case is done.
action: /head_of_section
consequence:
- Confirm
features:
- name: Completion certificates
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: completion_certificates
requires_group: head_of_section
transitions:
- from: checked
to: issued
label: Certificate signed
- from: checked
to: refused
label: Refused
- from: open
to: refused
label: Refused
- name: Exemptions
description: Sent in by An applicant whose plans break the zoning rules.
action: /head_of_section
consequence:
- Confirm
features:
- name: Exemptions
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: exemptions
requires_group: head_of_section
transitions:
- from: county_asked
to: refused
label: Refused
- from: county_heard
to: granted
label: Granted
- from: county_heard
to: refused
label: Refused
- from: open
to: refused
label: Refused
- name: Illegal building
description: Sent in by Someone who sees something going up behind their fence without permission or The front desk, when someone rings or comes in about building without permission.
action: /head_of_section
consequence:
- Confirm
features:
- name: Illegal building
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: illegal_building
requires_group: head_of_section
transitions:
- from: explained
to: fined
label: Weekly fine running
- name: Inspections
description: Sent in by An inspector on site, writing on a phone in a cold wind.
action: /head_of_section
consequence:
- Confirm
features:
- name: Inspections
description: Each row is one case and the stage it has reached. Another desk moves these.
resource:
source:
kind: kv
bucket: inspections
requires_group: head_of_section
transitions: []
- name: Objections
description: Sent in by A neighbour who got a notice in the post and does not agree with what is planned next door.
action: /head_of_section
consequence:
- Confirm
features:
- name: Objections
description: Each row is one case and the stage it has reached. Another desk moves these.
resource:
source:
kind: kv
bucket: objections
requires_group: head_of_section
transitions: []
- name: Paper objections
description: Sent in by The front desk, when an objection comes in on paper or over the counter.
action: /head_of_section
consequence:
- Confirm
features:
- name: Paper objections
description: Each row is one case and the stage it has reached. Another desk moves these.
resource:
source:
kind: kv
bucket: paper_objections
requires_group: head_of_section
transitions: []
- name: Temporary permissions
description: Sent in by An approved firm whose client wants to move in before everything is done.
action: /head_of_section
consequence:
- Confirm
features:
- name: Temporary permissions
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: temporary_permissions
requires_group: head_of_section
transitions:
- from: checked
to: issued
label: Temporary permission signed
- from: checked
to: refused
label: Refused
- from: open
to: refused
label: Refused
- name: Invite someone into Agencies
description: They get an account, a place in Agencies, and a one-time link to set their own password or passkey.
action: /head_of_section
consequence:
- Invite
invite:
group: agencies
features:
- name: Who
description: Their name, and the address the account and its one-time link go to.
requirements:
- name: name
label: Name
- name: email
label: Email
type: email
- name: Invite someone into Appeals board
description: They get an account, a place in Appeals board, and a one-time link to set their own password or passkey.
action: /head_of_section
consequence:
- Invite
invite:
group: appeals_board
features:
- name: Who
description: Their name, and the address the account and its one-time link go to.
requirements:
- name: name
label: Name
- name: email
label: Email
type: email
- name: Invite someone into Approved firms
description: They get an account, a place in Approved firms, and a one-time link to set their own password or passkey.
action: /head_of_section
consequence:
- Invite
invite:
group: approved_firms
features:
- name: Who
description: Their name, and the address the account and its one-time link go to.
requirements:
- name: name
label: Name
- name: email
label: Email
type: email
- name: Invite someone into Case officers
description: They get an account, a place in Case officers, and a one-time link to set their own password or passkey.
action: /head_of_section
consequence:
- Invite
invite:
group: case_officers
features:
- name: Who
description: Their name, and the address the account and its one-time link go to.
requirements:
- name: name
label: Name
- name: email
label: Email
type: email
- name: Invite someone into Front desk
description: They get an account, a place in Front desk, and a one-time link to set their own password or passkey.
action: /head_of_section
consequence:
- Invite
invite:
group: front_desk
features:
- name: Who
description: Their name, and the address the account and its one-time link go to.
requirements:
- name: name
label: Name
- name: email
label: Email
type: email
- name: Invite someone into Head of section
description: They get an account, a place in Head of section, and a one-time link to set their own password or passkey.
action: /head_of_section
consequence:
- Invite
invite:
group: head_of_section
features:
- name: Who
description: Their name, and the address the account and its one-time link go to.
requirements:
- name: name
label: Name
- name: email
label: Email
type: email
- name: Invite someone into Inspectors
description: They get an account, a place in Inspectors, and a one-time link to set their own password or passkey.
action: /head_of_section
consequence:
- Invite
invite:
group: inspectors
features:
- name: Who
description: Their name, and the address the account and its one-time link go to.
requirements:
- name: name
label: Name
- name: email
label: Email
type: email
- name: Invitations sent
description: Each invite and where it stands. A link that runs out unused can be sent again.
action: /head_of_section
consequence:
- Confirm
features:
- name: Who has been invited
description: Each row is one invitation. It is done by itself when the person signs in, and expired when the link ran out unused.
resource:
source:
kind: kv
bucket: portal_invites
requires_group: head_of_section
transitions:
- from: open
to: done
label: Is in
- from: expired
to: open
label: Send again
- from: expired
to: done
label: Is in
- name: Suggested changes to the site
description: What the people listed as responsible for a question have suggested changing. They are told each time a suggestion moves.
action: /head_of_section
consequence:
- Confirm
features:
- name: Suggestions
description: Each row is one suggestion, with the page it is about. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: portal_edit_suggestions
requires_group: head_of_section
transitions:
- from: open
to: discussed
label: We are looking at it
- from: open
to: done
label: The change is made
- from: open
to: declined
label: Will not be done
- from: discussed
to: done
label: The change is made
- from: discussed
to: declined
label: Will not be done
@@ -0,0 +1,104 @@
name: What brings you here?
description: |
We are the building authority for a municipality of twenty-one thousand people. Anyone who wants to build, demolish, divide a property or change what a building is used for has to come to us first. We check the drawings against the zoning map and the building regulations, we let the neighbours and the other authorities have their say, and then we approve or refuse. We also decide exemptions from the zoning rules, we inspect what is actually built, we sign off finished work, and we deal with building that was never applied for.
responsible:
name: Solveig Hauge
contact: byggesak@vestmark.example
alternatives:
- name: What we do
description: ''
features:
- name: Permission to build, demolish, divide a property or change what a building is used for
description: |
We check your drawings against the zoning map and the building regulations, let the neighbours and the other authorities have their say, and then approve or refuse. Every case is on the list here, so you and your neighbours can follow it the whole way, and object to it or appeal it from its own row.
- name: To file a building application for a client and see what is missing
description: |
Approved firms file applications for their clients here, see what is missing and ask for the completion certificate when the work is done.
- name: Latest from Vestmark kommune - Building and Planning
description: ''
features:
- name: Latest applications
description: What A homeowner who wants a garage, an extension, a new window or another change to their property or An approved architect or engineering firm filing on behalf of an owner sent in that is now received, papers missing, clock stopped, missing papers sent in, complete, clock running, out to neighbours and agencies, hearing over, recommendation written, approved, approved with conditions or refused. [All applications](/status/applications)
icon: lucide:list
resource:
source:
kind: kv
bucket: applications
public: true
states:
- open
- papers_missing
- papers_received
- complete
- in_hearing
- hearing_over
- recommended
- approved
- approved_with_conditions
- refused
empty: Nothing here yet.
jq: 'sort_by(.submitted_ms) | reverse | .[:3] | .[] | .responses |= {enclosed: .enclosed, kind_of_work: .kind_of_work, place: .place, property_address: .property_address, what_you_want_to_do: .what_you_want_to_do}'
link:
to: /status/applications/{id}
label: An exemption from the zoning rules, decided alongside their application
- name: Latest approved firm requests
description: What An architect or engineering firm that wants to file applications for owners sent in that is now on the list. [All approved firm requests](/status/approved_firm_requests)
icon: lucide:list
resource:
source:
kind: kv
bucket: approved_firm_requests
public: true
states:
- listed
empty: Nothing here yet.
jq: 'sort_by(.submitted_ms) | reverse | .[:3] | .[] | .responses |= {firm: .firm, qualified_for: .qualified_for, registration_number: .registration_number}'
- name: Build
description: For You want to build, demolish, divide a property or change what a building is used for.
action: /build
consequence:
- Continue
features:
- name: ''
description: A meeting with a case officer, and a written note of what we told them, Permission to build, demolish, divide a property or change what a building is used for.
- name: Firm
description: For You are an architect or an engineering firm filing on behalf of owners.
action: /firm
consequence:
- Continue
features:
- name: ''
description: To file a building application for a client and see what is missing, A completion certificate for the finished work, A temporary permission to use the building, To be approved by us and put on the list of firms that may file.
- name: To tell us, so that we go and look
description: For Someone who sees something going up behind their fence without permission.
action: /received/illegal-building-report
consequence:
- Send
record_as: illegal_building
features:
- name: What happens next
description: It is reported, then we have been and looked, then owner written to, then owner has explained, then weekly fine running, and ends applied for properly, taken down or nothing illegal found.
icon: lucide:route
- name: Who reads it
description: Case officers. Questions go to Solveig Hauge at byggesak@vestmark.example.
icon: lucide:users
- name: Details
requirements:
- name: where
label: Where
type: text
- name: what_is_being_built
label: What is being built
type: textarea
- name: place
label: Place
type: location
optional: true
- name: name
label: Name
type: text
optional: true
- name: phone
label: Phone
type: tel
optional: true
@@ -0,0 +1 @@
qualifies: inspectors
@@ -0,0 +1,132 @@
name: What needs doing?
description: Everything inspectors looks after.
responsible:
name: Solveig Hauge
contact: byggesak@vestmark.example
alternatives:
- name: Applications
description: Sent in by A homeowner who wants a garage, an extension, a new window or another change to their property or An approved architect or engineering firm filing on behalf of an owner.
action: /inspectors
consequence:
- Confirm
features:
- name: Applications
description: Each row is one case and the stage it has reached. Another desk moves these.
resource:
source:
kind: kv
bucket: applications
requires_group: inspectors
transitions: []
- name: Completion certificates
description: Sent in by An approved firm whose work on a case is done.
action: /inspectors
consequence:
- Confirm
features:
- name: Completion certificates
description: Each row is one case and the stage it has reached. Another desk moves these.
resource:
source:
kind: kv
bucket: completion_certificates
requires_group: inspectors
transitions: []
- name: Illegal building
description: Sent in by Someone who sees something going up behind their fence without permission or The front desk, when someone rings or comes in about building without permission.
action: /inspectors
consequence:
- Confirm
features:
- name: Illegal building
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: illegal_building
requires_group: inspectors
transitions:
- from: open
to: inspected
label: We have been and looked
- name: Inspections
description: Sent in by An inspector on site, writing on a phone in a cold wind.
action: /inspectors
consequence:
- Confirm
features:
- name: Inspections
description: Each row is one case. The buttons record what you have just done with it.
resource:
source:
kind: kv
bucket: inspections
requires_group: inspectors
transitions:
- from: open
to: to_put_right
label: To be put right, then we go back
- from: open
to: as_approved
label: As approved
- from: to_put_right
to: as_approved
label: As approved
- name: Temporary permissions
description: Sent in by An approved firm whose client wants to move in before everything is done.
action: /inspectors
consequence:
- Confirm
features:
- name: Temporary permissions
description: Each row is one case and the stage it has reached. Another desk moves these.
resource:
source:
kind: kv
bucket: temporary_permissions
requires_group: inspectors
transitions: []
- name: To write up what was found on a case and set a date for what must be put right
description: For An inspector on site, writing on a phone in a cold wind.
action: /inspectors/inspection
consequence:
- Open
- name: Invite someone into Inspectors
description: They get an account, a place in Inspectors, and a one-time link to set their own password or passkey.
action: /inspectors
consequence:
- Invite
invite:
group: inspectors
features:
- name: Who
description: Their name, and the address the account and its one-time link go to.
requirements:
- name: name
label: Name
- name: email
label: Email
type: email
- name: Invitations sent
description: Each invite and where it stands. A link that runs out unused can be sent again.
action: /inspectors
consequence:
- Confirm
features:
- name: Who has been invited
description: Each row is one invitation. It is done by itself when the person signs in, and expired when the link ran out unused.
resource:
source:
kind: kv
bucket: portal_invites
requires_group: inspectors
transitions:
- from: open
to: done
label: Is in
- from: expired
to: open
label: Send again
- from: expired
to: done
label: Is in
@@ -0,0 +1,5 @@
name: What happens now?
description: It has reached our inspectors.
alternatives:
- name: We read it and come back to you
description: Questions in the meantime go to Solveig Hauge at byggesak@vestmark.example.
@@ -0,0 +1,43 @@
followup: false
name: Inspection?
description: ''
responsible:
name: Solveig Hauge
contact: byggesak@vestmark.example
alternatives:
- name: To write up what was found on a case and set a date for what must be put right
description: For An inspector on site, writing on a phone in a cold wind.
action: /inspectors/inspection-sent
consequence:
- Send
record_as: inspections
features:
- name: What happens next
description: It is inspected, then to be put right, then we go back, and ends as approved.
icon: lucide:route
- name: Who reads it
description: Inspectors. Questions go to Solveig Hauge at byggesak@vestmark.example.
icon: lucide:users
- name: Details
requirements:
- name: application_reference
label: Application reference
type: text
- name: finding
label: Finding
type: select
options:
- As approved
- Something is wrong
- name: what_is_wrong
label: What is wrong
type: textarea
optional: true
- name: put_right_by
label: Put right by
type: date
optional: true
- name: place
label: Place
type: location
optional: true
@@ -0,0 +1,5 @@
name: What happens now?
description: It has reached our case officers.
alternatives:
- name: We read it and come back to you
description: Questions in the meantime go to Solveig Hauge at byggesak@vestmark.example.
@@ -0,0 +1,10 @@
name: What happens now?
description: It has reached our case officers.
alternatives:
- name: We read it and come back to you
description: Questions in the meantime go to Solveig Hauge at byggesak@vestmark.example.
- name: See all applications
description: ''
action: /status/applications
consequence:
- Open
@@ -0,0 +1,5 @@
name: What happens now?
description: It has reached our case officers.
alternatives:
- name: We read it and come back to you
description: Questions in the meantime go to Solveig Hauge at byggesak@vestmark.example.
@@ -0,0 +1,10 @@
name: What happens now?
description: It has reached our case officers.
alternatives:
- name: We read it and come back to you
description: Questions in the meantime go to Solveig Hauge at byggesak@vestmark.example.
- name: See all approved firm requests
description: ''
action: /status/approved_firm_requests
consequence:
- Open
@@ -0,0 +1,5 @@
name: What happens now?
description: It has reached our case officers.
alternatives:
- name: We read it and come back to you
description: Questions in the meantime go to Solveig Hauge at byggesak@vestmark.example.
@@ -0,0 +1,5 @@
name: What happens now?
description: It has reached our case officers.
alternatives:
- name: We read it and come back to you
description: Questions in the meantime go to Solveig Hauge at byggesak@vestmark.example.
@@ -0,0 +1,5 @@
name: What happens now?
description: It has reached our case officers.
alternatives:
- name: We read it and come back to you
description: Questions in the meantime go to Solveig Hauge at byggesak@vestmark.example.
@@ -0,0 +1,126 @@
name: An exemption from the zoning rules, decided alongside their application?
description: For An applicant whose plans break the zoning rules, or A neighbour who got a notice in the post and does not agree with what is planned next door, or Anyone with an interest in a decision, the applicant or a neighbour.
responsible:
name: Solveig Hauge
contact: byggesak@vestmark.example
alternatives:
- name: An exemption from the zoning rules, decided alongside their application
description: For An applicant whose plans break the zoning rules.
action: /received/exemption
consequence:
- Send
record_as: exemptions
features:
- name: What you need
description: An application with us; the exemption rides along with it and is asked for from its row on the list of cases.
icon: lucide:key
- name: What happens next
description: It is received, then county asked, then county has answered or its deadline has passed, and ends granted or refused.
icon: lucide:route
- name: Who reads it
description: Case officers. Questions go to Solveig Hauge at byggesak@vestmark.example.
icon: lucide:users
- name: Details
requirements:
- name: name
label: Name
type: text
value: '{user.name}'
- name: email
label: Email
type: email
value: '{user.email}'
- name: rule_it_breaks
label: Rule it breaks
type: text
- name: why_it_should_be_allowed
label: Why it should be allowed
type: textarea
- name: applications
type: record
of: applications
value: '{key}'
- name: To object to an application and have the objection answered in the decision
description: For A neighbour who got a notice in the post and does not agree with what is planned next door.
action: /received/objection
consequence:
- Send
record_as: objections
features:
- name: What you need
description: The application must still be out for hearing; objections are taken until the six weeks are up.
icon: lucide:key
- name: What happens next
description: It is received, then registered on the case, then answered by the applicant, and ends addressed in the decision.
icon: lucide:route
- name: Who reads it
description: Case officers. Questions go to Solveig Hauge at byggesak@vestmark.example.
icon: lucide:users
- name: Details
requirements:
- name: name
label: Name
type: text
value: '{user.name}'
- name: email
label: Email
type: email
value: '{user.email}'
- name: your_property
label: Your property
type: text
- name: objection
label: Objection
type: textarea
- name: phone
label: Phone
type: tel
optional: true
- name: applications
type: record
of: applications
value: '{key}'
- name: To appeal a decision we have made
description: For Anyone with an interest in a decision, the applicant or a neighbour.
action: /received/appeal
consequence:
- Send
record_as: appeals
features:
- name: What you need
description: A decision on the application, made no more than three weeks ago.
icon: lucide:key
- name: What happens next
description: It is received, then we are going through it ourselves, then sent to the appeals board, and ends we changed our own decision, decision upheld by the board, decision overturned by the board or dismissed.
icon: lucide:route
- name: Who reads it
description: Case officers. Questions go to Solveig Hauge at byggesak@vestmark.example.
icon: lucide:users
- name: Details
requirements:
- name: name
label: Name
type: text
value: '{user.name}'
- name: email
label: Email
type: email
value: '{user.email}'
- name: your_interest
label: Your interest
type: select
options:
- I am the applicant
- I am a neighbour
- Other
- name: grounds
label: Grounds
type: textarea
- name: phone
label: Phone
type: tel
optional: true
- name: applications
type: record
of: applications
value: '{key}'
@@ -0,0 +1,32 @@
name: What has been sent in about applications?
description: What A homeowner who wants a garage, an extension, a new window or another change to their property or An approved architect or engineering firm filing on behalf of an owner sent in that is now received, papers missing, clock stopped, missing papers sent in, complete, clock running, out to neighbours and agencies, hearing over, recommendation written, approved, approved with conditions or refused.
responsible:
name: Solveig Hauge
contact: byggesak@vestmark.example
alternatives:
- name: Applications
description: ''
features:
- name: Applications
description: Each row is one case and the stage it has reached. Names and contact details are not shown here.
resource:
source:
kind: kv
bucket: applications
public: true
states:
- open
- papers_missing
- papers_received
- complete
- in_hearing
- hearing_over
- recommended
- approved
- approved_with_conditions
- refused
empty: Nothing here yet.
jq: 'sort_by(.submitted_ms) | reverse | .[] | .responses |= {enclosed: .enclosed, kind_of_work: .kind_of_work, place: .place, property_address: .property_address, what_you_want_to_do: .what_you_want_to_do}'
link:
to: /status/applications/{id}
label: An exemption from the zoning rules, decided alongside their application
@@ -0,0 +1,20 @@
name: What has been sent in about approved firm requests?
description: What An architect or engineering firm that wants to file applications for owners sent in that is now on the list.
responsible:
name: Solveig Hauge
contact: byggesak@vestmark.example
alternatives:
- name: Approved firm requests
description: ''
features:
- name: Approved firm requests
description: Each row is one case and the stage it has reached. Names and contact details are not shown here.
resource:
source:
kind: kv
bucket: approved_firm_requests
public: true
states:
- listed
empty: Nothing here yet.
jq: 'sort_by(.submitted_ms) | reverse | .[] | .responses |= {firm: .firm, qualified_for: .qualified_for, registration_number: .registration_number}'
@@ -0,0 +1,16 @@
title: Vestmark kommune - Building and Planning
lang: en
mail:
from: Vestmark kommune Building and Planning <post@vestmark.example>
reply_to: byggesak@vestmark.example
invite:
subject: Your account at {site_name}
body: |-
Hello {name},
{site_name} has made you an account and added you to {group}. Your username is {username}.
Set your password here before {expires}:
{link}
After that you sign in at {site}.
File diff suppressed because it is too large Load Diff
@@ -19,7 +19,8 @@
"questions/status/oppslag/[key].yaml": { "questions/status/oppslag/[key].yaml": {
"question": "Vil du låne ut, eller låne, det som står i oppslaget?", "question": "Vil du låne ut, eller låne, det som står i oppslaget?",
"description": "Du svarer på ett oppslag. Den som la det ut får e-posten din med en gang, og tar kontakt.", "description": "Du svarer på ett oppslag. Den som la det ut får e-posten din med en gang, og tar kontakt.",
"form": { "forms": {
"melde-seg": {
"heading": "Si fra til den som la ut oppslaget", "heading": "Si fra til den som la ut oppslaget",
"description": "Legg igjen e-posten din, så får de vite at du kan låne ut, eller vil låne.", "description": "Legg igjen e-posten din, så får de vite at du kan låne ut, eller vil låne.",
"button": "Send svar", "button": "Send svar",
@@ -45,6 +46,7 @@
"hilsen": "Jeg har en stige du kan låne i helga" "hilsen": "Jeg har en stige du kan låne i helga"
} }
} }
}
}, },
"questions/received/melde-seg.yaml": { "questions/received/melde-seg.yaml": {
"question": "Hva skjer nå?", "question": "Hva skjer nå?",
+25 -13
View File
@@ -934,17 +934,19 @@ pub fn fallback_words(plan: &Plan) -> BTreeMap<String, Value> {
}), }),
); );
} }
// A page per record of a public need, where another need answers // A page per record of a public need, where other needs answer it
// it: the record's own words come from the record, so the page // - an objection and an appeal both belong to the application. The
// only has to ask and hold the form. // record's own words come from the record, so the page only has to
for need in plan.needs.iter().filter(|n| n.about.is_some()) { // ask and hold the forms, one per answering need.
let parent = plan.parent_of(need).expect("validated"); for parent in &plan.needs {
let answers = plan.answers_to(parent);
let Some(first) = answers.first() else { continue };
words.insert( words.insert(
answer_page_path(&parent.lands_in), answer_page_path(&parent.lands_in),
json!({ json!({
"question": format!("{}?", capitalize(&need.wants)), "question": format!("{}?", capitalize(&first.wants)),
"description": format!("For {}.", need.who), "description": format!("For {}.", answers.iter().map(|n| n.who.as_str()).collect::<Vec<_>>().join(", or ")),
"form": form(need), "forms": answers.iter().map(|n| (n.id.clone(), form(n))).collect::<Map<_, _>>(),
}), }),
); );
} }
@@ -1781,8 +1783,11 @@ pub fn render(plan: &Plan, words: &BTreeMap<String, Value>) -> anyhow::Result<BT
// A page per record of a board, holding the form that answers it. // A page per record of a board, holding the form that answers it.
// Dynamic: portal serves `/status/<bucket>/<id>` from it, and the // Dynamic: portal serves `/status/<bucket>/<id>` from it, and the
// form's record field carries that id. // form's record field carries that id.
for need in plan.needs.iter().filter(|n| n.about.is_some()) { for parent in &plan.needs {
let parent = plan.parent_of(need).expect("validated"); let answers = plan.answers_to(parent);
if answers.is_empty() {
continue;
}
let path = answer_page_path(&parent.lands_in); let path = answer_page_path(&parent.lands_in);
let w = &words[&path]; let w = &words[&path];
files.insert( files.insert(
@@ -1791,7 +1796,7 @@ pub fn render(plan: &Plan, words: &BTreeMap<String, Value>) -> anyhow::Result<BT
"name": s(&w["question"]), "name": s(&w["question"]),
"description": s(&w["description"]), "description": s(&w["description"]),
"responsible": responsible, "responsible": responsible,
"alternatives": [form_alternative(plan, need, &w["form"], &public_followup(need))], "alternatives": answers.iter().map(|n| form_alternative(plan, n, &w["forms"][&n.id], &public_followup(n))).collect::<Vec<_>>(),
}), }),
); );
} }
@@ -2004,7 +2009,7 @@ pub fn render(plan: &Plan, words: &BTreeMap<String, Value>) -> anyhow::Result<BT
(None, Some(door), _) => ("/".to_string(), s(&front["doors"][door]["heading"]).to_string(), 2), (None, Some(door), _) => ("/".to_string(), s(&front["doors"][door]["heading"]).to_string(), 2),
// An answer enters on the record's own page, which // An answer enters on the record's own page, which
// the board's row links to. // the board's row links to.
(None, None, Some(parent)) => (answer_page(&parent.lands_in), s(&words[&answer_page_path(&parent.lands_in)]["form"]["heading"]).to_string(), 1), (None, None, Some(parent)) => (answer_page(&parent.lands_in), s(&words[&answer_page_path(&parent.lands_in)]["forms"][&n.id]["heading"]).to_string(), 1),
(None, None, None) => ("/".to_string(), s(&front["needs"][&n.id]["heading"]).to_string(), 1), (None, None, None) => ("/".to_string(), s(&front["needs"][&n.id]["heading"]).to_string(), 1),
}; };
let mut need = json!({ let mut need = json!({
@@ -2052,7 +2057,7 @@ fn words_prompt(plan: &Plan, path: &str, fallback: &Value) -> String {
} else if path.ends_with("/index.yaml") { } else if path.ends_with("/index.yaml") {
"a desk: the page one role inside the business works from. Under `buckets`, each entry is a list of cases; `moves` are the buttons that move a case from one stage to the next (key `from->to`), so label each with what the person has just done. Under `links` are pages this role can open. Under `invites`, each entry is a form that invites a person into that group - they get an account and a one-time link - and `invited` is the list of invites sent, where `again` is the button that sends an invite whose link ran out once more. `suggestions`, on the desk that has it, is the list of changes the people responsible for a page have suggested: `looking`, `changed` and `declined` are its buttons." "a desk: the page one role inside the business works from. Under `buckets`, each entry is a list of cases; `moves` are the buttons that move a case from one stage to the next (key `from->to`), so label each with what the person has just done. Under `links` are pages this role can open. Under `invites`, each entry is a form that invites a person into that group - they get an account and a one-time link - and `invited` is the list of invites sent, where `again` is the button that sends an invite whose link ran out once more. `suggestions`, on the desk that has it, is the list of changes the people responsible for a page have suggested: `looking`, `changed` and `declined` are its buttons."
} else if path.ends_with("/[key].yaml") { } else if path.ends_with("/[key].yaml") {
"a page one record of a public list opens to. This is NOT where a notice is posted: the visitor has read somebody else's notice on the board and is answering it, and their answer is mailed straight to the person who posted it. `question` asks the visitor whether they can do what the notice asks; `form` is the form they fill, at most an address and a line. Nobody at a desk passes the answer on, so never say so." "a page one record of a public list opens to. This is NOT where a notice is posted: the visitor has read somebody else's record on the list (a notice, an application) and is answering it. `question` asks the visitor what they have to say to it; under `forms`, each entry is one kind of answer (an objection, an appeal, an offer to lend), with the form behind it. An answer that mails the record's owner goes straight to them; nobody at a desk passes it on, so never say so."
} else if path.contains("/received/") || path.ends_with("-sent.yaml") { } else if path.contains("/received/") || path.ends_with("-sent.yaml") {
"a page shown right after someone has sent a form. Say who reads it, when they answer, and what happens next." "a page shown right after someone has sent a form. Say who reads it, when they answer, and what happens next."
} else { } else {
@@ -2986,6 +2991,13 @@ mod invite_tests {
assert_eq!(alt["action"], "/received/answer"); assert_eq!(alt["action"], "/received/answer");
let reqs = alt["features"].as_array().unwrap().last().unwrap()["requirements"].as_array().unwrap(); let reqs = alt["features"].as_array().unwrap().last().unwrap()["requirements"].as_array().unwrap();
assert_eq!(reqs[0]["value"], "{user.email}"); assert_eq!(reqs[0]["value"], "{user.email}");
// Two needs about the same record share its page, one form each.
let two: Plan = serde_yaml::from_str(&format!("{BOARD} - id: borrow\n who: en nabo som vil låne det\n wants: å låne det\n about: notice\n lands_in: laan\n handled_by: redaktor\n stages: [open, lest]\n done_when: [lest]\n max_fields: 1\n collects:\n - {{ name: email, type: email }}\n")).unwrap();
two.validate().unwrap();
let files = render(&two, &fallback_words(&two)).unwrap();
let page: Value = serde_yaml::from_str(&files["questions/status/oppslag/[key].yaml"]).unwrap();
let buckets: Vec<&str> = page["alternatives"].as_array().unwrap().iter().map(|a| a["record_as"].as_str().unwrap()).collect();
assert_eq!(buckets, ["svar", "laan"]);
assert_eq!(reqs[1]["type"], "record"); assert_eq!(reqs[1]["type"], "record");
assert_eq!(reqs[1]["of"], "oppslag"); assert_eq!(reqs[1]["of"], "oppslag");
assert_eq!(reqs[1]["value"], "{key}"); assert_eq!(reqs[1]["value"], "{key}");