SaaS.Dev

What an App reads from a Noun: depth

Representation, field types, relationships, lifecycle states and Events: what an App draws from each fact a Noun declares, traced through one Lease.

An API needs a Noun's types to check a call, and nothing more. An App reads more from the same file: the field that names a record, the field order, each reference, and the Verbs that move it.

One Noun, traced to its screens

leaseclock.com tracks lease renewal dates for small property managers. Its Startup declares two Nouns, Property and Lease, and the Admin reads every fact below from those two files.

nouns/Lease.mdx
---
extends: [Thing]
properties:
  residentName: string
  residentEmail?: email
  listingUrl?: url
  startsOn: date
  endsOn: date
  monthlyRent: number
  status: active | renewed | terminated
  notes?: text
  terms?: json
  documents?: string[]
  property: Property
verbs:
  renew: {}
  terminate: {}
---
A Lease is one resident's agreement on one unit of a Property, from signing to renewal.
nouns/Property.mdx
---
properties:
  name: string
  address?: string
  units: integer
---
A Property is one building a manager rents out, unit by unit.
Fact in the fileThe API reads it asThe Admin draws from itRule
The Noun's name, Leasethe route /leases and the type Leasethe key leases, the labels Lease and Leaseskey, labels
The first one-line text field, residentNamea property like any otherthe record's name: the page title, every reference cell, every picker choicerepresentation
The order of the propertiesnothingthe order of the list columns, at most 7list-columns
Each property's name, such as monthlyRentthe JSON keythe label Monthly Rentlabels
Each property's typethe check on every writethe control in each screenField kinds and their controls
A ? on a namean optional inputa form input that accepts an empty valuerequired-input
property: Propertythe id of a Propertythe Property by its name, linked, and a pickerreference-forward
status: active | renewed | terminatedthe lifecycle, moved by Verbsa text column and a text boxcontrol-text
renew: {}, terminate: {}two routes, each returning an Actiontwo buttons on each row, the record page and the edit formverb-action

Representation: the field that names a record

Every record shows somewhere as one short string: a page title, a cell that points at it, a choice in a picker. The Admin takes the first of name, title, label, email and slug that holds one line of text. Failing those, it takes the first one-line text field, then the id.

Property has name, so a lease's property cell reads 14 Elm Street. Lease has none of the five, so residentName names it: Maya Ortiz. Without one of those five names, the first one-line field wins, so the declared order picks the name.

PlanChoosing the name by hand

In the design, a Noun file names its representation field directly, overriding the guess. Its rule, representation-override, waits for code that serves it.

Fields and relationships

The API ignores the order of properties. The Admin keeps it: the list shows the first 7 short fields in declared order, properties before references. Lease declares 7 short properties before property, so the list leaves property out and the record page shows it.

A property typed with another Noun is a forward reference. The record page and the list show the referenced record by its name and link to it, and the forms offer a picker that searches. The forms never require a reference, even one declared without ?.

RelationshipDeclared in a Noun fileIn the Admin
Lease points at one Propertyproperty: Property on Leasethe Property by its name, linked; a searching picker in the forms
Property holds many Lease recordsno keynothing on the Property record page

PlanThe other end of a relationship

In the design, the Property record page lists its leases, by each lease's name and its next short fields. Its rule, related-list, waits: no Noun-file key declares the other end of a relationship.

Lifecycle states

status: active | renewed | terminated lists the lifecycle in order. create starts every lease at active, and only a Verb moves it. The Admin shows status as text in the list and on the record page.

The create and edit forms offer status as a one-line text box. The hub's Noun-file rule says no create or update input takes it.

PlanStates moved only by Verbs

In the design, the forms leave status out, and a Verb button is the only way to change it. Its rule, state-moves-by-verb, waits. So does blocked-action, which removes a screen or the delete button for a blocked standard Verb: no Noun-file key blocks one.

Verbs and Events

Each Verb beyond create, get, list, update and delete becomes a button labeled from its name: renew reads Renew. The button runs the Verb on its record, and the Verb's rules decide.

A completed call shows a notice and reloads the record (verb-result). A refused one shows the Verb's reason and leaves the screen as it was (refusal-message).

Each completed Verb also records an Event, such as Lease.renewed. No printed rule draws a screen part from an Event: the reload after a Verb shows what it changed. A Verb's declared inputs are the subject of Verb inputs: what a form needs.

Contents