Updraft ExtensionsPreview

Authoring documentation

How to add a resource, an example, or a guide to this site — and the one rule that keeps the pages consistent.

The rule #

Structure is data. Narrative is content.

A resource’s machine-readable schema lives in data/schemas/. Its prose lives in content/resources/. The schema drives the explorer, the property reference, the return values, the generated templates, the IAM policy, the search index and the cross-reference graph — from one source, so they cannot disagree.

Prose adds only what a schema cannot: why the resource exists, what it is commonly paired with, and what will bite you.

If you find yourself writing a property’s type or requiredness in prose, it belongs in the schema instead.

Adding a resource #

Two files.

1. The schema #

data/schemas/<provider>/<service>/<name>.yaml. The directory layout is free — the only rule is that a schema document is any map carrying a typeName key.

typeName: Updraft::Example::Thing
provider: updraft            # aws | updraft — drives the catalogue facets
providerTitle: Updraft Extensions
service: Example
serviceTitle: Updraft Example
category: Configuration
status: stable               # stable | preview | deprecated
identifier: ThingId
tagProperty: Tags            # omit if the type is not taggable

summary: >-
  One sentence. Appears in the hero, the catalogue card, and the search index.

related:
  - AWS::S3::Bucket          # resolved by type name, not by path

properties:
  Name:
    type: string             # string integer number boolean object array map json
    required: true           # true | false | conditional
    order: 1                 # tie-break within the requiredness band
    updates: none            # none | some | replacement | na
    createOnly: true         # adds the lock icon
    summary: One line, shown on the collapsed row.
    description: |
      Markdown. Shown when the row is expanded.
    constraints:
      minLength: 1
      maxLength: 64
      pattern: '^[a-z-]+$'
      patternNote: Explain the pattern in words. Regexes are not documentation.
    enum: [A, B]
    default: A
    examples: ["a-real-looking-value"]
    notes:
      - kind: gotcha         # note tip important warning caution gotcha remarks
        title: Optional heading
        text: |
          Markdown.

definitions:
  NestedType:
    title: NestedType
    summary: One line.
    properties: {}           # same shape as above, recursively

attributes:
  Arn:
    type: string
    summary: What it is.
    example: "arn:aws:…"

ref:
  short: Thing ID            # shown in the fact strip
  returns: |
    Markdown, shown in the return-values section.
  example: thing-2f8a1c94

permissions:
  create: [service:Action]
  read: []                   # an explicit empty list means "no calls", and
  update: []                 # renders differently from an absent key
  delete: []

Referencing a nested type uses ref: against a key in definitions:

  Source:
    type: object
    ref: S3Location          # a plain object
  Rules:
    type: array
    items:
      ref: LifecycleRule     # an array of them
  Labels:
    type: map
    values:
      type: string           # a map of scalars

Recursive definitions are safe — the renderer tracks which definitions are open on the current path and renders a link back instead of looping.

2. The page #

content/resources/<provider>/<service>/<name>/_index.md. It must be _index.md (a branch bundle) so that examples can live underneath it.

---
title: Updraft::Example::Thing     # the full type name
linkTitle: Thing                   # short form, for the nav tree
type: resource                     # selects the resource layout
schema: Updraft::Example::Thing    # links the page to its schema
weight: 10
---

Everything after the front matter is the narrative slot, rendered between the minimal template and the property explorer. Write an ## Overview, then whatever remarks and worked snippets belong there.

Adding an example #

A markdown file beside the resource’s _index.md:

---
title: A sentence describing the scenario
linkTitle: Short form for the nav
type: example
weight: 10
level: Intermediate       # Beginner | Intermediate | Advanced
time: 15 min
diagram: true
uses:                     # type names; rendered as links where documented
  - AWS::S3::Bucket
lede: >-
  Two sentences on what this shows and why it is not the obvious approach.
---

An example earns its own page when it has a diagram, more than one resource, or something to say about failure modes and teardown. Anything smaller belongs inline on the resource page.

The shortcode vocabulary #

Callouts #

{{< note >}} … {{< /note >}}
{{< tip >}}  {{< important >}}  {{< warning >}}  {{< caution >}}
{{< gotcha title="Optional heading" >}} … {{< /gotcha >}}
{{< remarks >}} … {{< /remarks >}}

See documentation conventions for when each is appropriate. gotcha is the valuable one — reserve it.

Code tabs #

{{< tabs group="lang" default="yaml" >}}
{{< tab label="YAML" key="yaml" >}}
```yaml
…

{{< /tab >}} {{< tab label=“CDK (TypeScript)” key=“cdk-ts” >}} … {{< /tab >}} {{< /tabs >}}


Use the standard keys — `yaml`, `json`, `cdk-ts`, `cdk-py` — so a reader's choice
follows them across every tab set on the site and across visits.

### Input and result

```text
{{< io split="true" inLabel="Template" outLabel="Result" >}}
{{< io-in >}} … {{< /io-in >}}
{{< io-out >}} … {{< /io-out >}}
{{< /io >}}

And the one-liner, for showing what an expression resolves to:

{{< resolves in="!Ref AppConfig" out="doc-2f8a1c94" note="a handle" >}}

Cross-references #

{{< type "AWS::S3::Bucket" >}}          links to the resource page
{{< prop "BucketEncryption" >}}         links to a property on this page
{{< prop "BucketEncryption.ServerSideEncryptionConfiguration" >}}

Diagrams #

Diagrams are hand-authored inline SVG using the dg-* class vocabulary. They are theme-aware, selectable, searchable, and need no renderer.

{{< diagram caption="What the reader should take away." alt="Description for screen readers." >}}
<svg class="dg" viewBox="0 0 760 200" role="img">
  <rect class="dg-node dg-node--accent" x="12" y="40" width="120" height="52" rx="6"/>
  <text class="dg-title" x="72" y="64" text-anchor="middle">Client</text>
  <text class="dg-sub"   x="72" y="80" text-anchor="middle">https://</text>
  <path class="dg-edge dg-edge--accent" d="M136 66 H200"/>
</svg>
{{< /diagram >}}

The vocabulary:

ClassUse
dg-nodeA box. --alt for a secondary fill, --accent for emphasis, --ghost for something outside the system.
dg-zoneA dashed boundary — a VPC, an account, a trust boundary. --solid for a hard one.
dg-edgeA line with an arrowhead. --accent, --dashed, --plain (no head).
dg-title / dg-sub / dg-labelText at three weights. dg-sub is monospaced, for identifiers.
dg-zonelabelSmall caps label for a zone.
dg-step / dg-stepnumA numbered circle, for ordered flows.

Checking your work #

make serve      # live reload at http://localhost:1313
make build      # production build, fails on a broken reference
make check      # link and markup checks

The build fails — it does not warn — when a page names a schema that does not exist, when a property references an undefined nested type, or when a tabs block has no children. A resource page that renders blank is worse than one that does not render at all.