diff --git a/docs/reference.md b/docs/reference.md index 913c4fb..ba76375 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -48,6 +48,7 @@ The quick lookup surface: one line and a minimal snippet per construct. For rule | [`notifications`](/spec/glue#notifications) | email on an event of the axis | | [notify link placeholders](/spec/glue#links-back-to-the-application-recordurl-inboxurl-appurl) | `{recordUrl}` / `{inboxUrl}` / `{appUrl}` - a message that carries the way back into the application | | [the notify block / `attach: print`](/spec/glue#the-notify-block-and-attach-print) | send a message about a record - with the record's own document attached - from a process step, a transition or a schedule | +| [`fileName`](/spec/presentation#naming-the-rendered-file-filename) | the name a rendered document is stored or attached under - a pattern over the record's own data | | [`schedules`](/spec/glue#schedules) | cron: notify or generate records per matching row; `where` values may be moments relative to the firing | | [`integrations`](/spec/glue#integrations-outbound-http) | outbound HTTP on a data change | | [`inbound`](/spec/glue#inbound-arrivals-from-outside) | records arriving from outside: a webhook, a queue/topic message, a dropped file | diff --git a/docs/spec/presentation.md b/docs/spec/presentation.md index b386a10..54d2173 100644 --- a/docs/spec/presentation.md +++ b/docs/spec/presentation.md @@ -249,6 +249,41 @@ The print template is written **create-if-absent** and never regenerated over. A To add a language, add a file under a sibling language folder (`.../Print/bg/standard.print`); the print action asks which to use when several exist. +### Naming the rendered file - `fileName` + +A document is rendered to a file in two places - the versioned copy a [`function: Snapshot`](/spec/entities#attachments-and-snapshots) child mints, and the copy a [notify block](/spec/glue#the-notify-block-and-attach-print) attaches. Both accept a `fileName` pattern: literal text and `{token}` interpolations over the record being rendered. + +```yaml +entities: + - name: SalesInvoiceCopy + function: Snapshot + fileName: "{number}_{date:yyyyMMdd}_{company.shortName|company.name}" + relations: + - { name: salesInvoice, kind: manyToOne, to: SalesInvoice, composition: true, required: true } +``` + +| Token | Renders | +| --- | --- | +| `{field}` | a field of the rendered record | +| `{relation.field}` | a field of a one-hop to-one relation of it | +| `{field:pattern}` | a date or timestamp field in the given date-format pattern | +| `{A\|B}` | the first non-blank of the listed operands, left to right | +| `{Version}` | the copy's version (a snapshot only) | + +Paths use the authored field and relation names - the same vocabulary a notify `subject` interpolates. A snapshot's pattern resolves against its **document master** (the copy row itself holds only the stored file's coordinates); a notify block's against the record that block renders. + +The name is the only thing a file carries once it leaves the application: an archive is browsed and searched by it, an attachment arrives in a mailbox with no application around it, and a hand-off to an accountant or an auditor is a folder plus a naming convention agreed in advance. A folder of `Order 42 v1.pdf`, `Order 43 v1.pdf` is unusable at the exact moment it matters. + +::: info Normative +An interpolated value is sanitized before it enters the name: trimmed, internal whitespace collapsed to a single separator, and characters the storage or transport cannot carry removed. Non-ASCII characters are preserved - whether a name is transliterated is an application's data convention, not the format's. Literal text between tokens is emitted verbatim: the author owns the separators. + +A token whose value is blank renders empty. A token naming a field or relation the entity does not have is rejected at authoring time, not rendered empty - a silently dropped token produces exactly the indistinguishable names this construct removes. Also rejected: a pattern that interpolates nothing, unbalanced or nested braces, a date format on a field that is not a date or timestamp, a format the formatter does not accept, and a multi-hop path. + +`{Version}` is rejected where no version exists; a snapshot pattern that does not place it has the version appended, because two versions of one copy must never share a name. On a notify block `fileName` requires an `attach`, and where the attached document is rendered once for a whole fan-out only fields of that record are readable. + +Absent a pattern, an implementation supplies a default - and the same default for both renders; a document's own number is used where it declares one. +::: + ## See also - [Entities & fields](/spec/entities) — `function`, `label` and the status relation these surfaces read.