# 0040. One structured data graph; a location is a SelfStorage

- **Status:** Accepted
- **Date:** 2026-09-24

## Context

`JsonLdHelper` wrote a `WebPage` with a breadcrumb and, on news items, a `NewsArticle`. Nothing described the
company, the site, the locations or the units — the things a search engine or an assistant would be asked about.

## Decision

`app\helpers\StructuredData` builds Schema.org nodes; `View::registerStructuredData()` writes **one `@graph`**
per page: `Organization` and `WebSite` (with the search action) everywhere, the visible breadcrumb, then what the
action pushes onto `Controller::$structuredData`: `NewsArticle`, `Service`, `FAQPage` (FAQ and tips),
**`SelfStorage`** for a location (address, coordinates), and a `Product` for a unit whose `Offer` is the
**gross** monthly rent (`price1M`, `UnitPriceSpecification` with `unitCode: MON`), availability from
`AvailabilityService`. Node identifiers are absolute (home URL + fragment). A builder that cannot fill its
required fields returns null and is left out.

## Alternatives

- **`Organization` only**, as Molino does. There the business is not a place to walk into; here a location is
  exactly that, with coordinates on the record.
- **`Accommodation` or `Place` for a unit.** Accommodation is for sleeping in; a unit is rented as a product.
- **A script tag per node.** The organization would be repeated, slightly differently, in every node.

## Consequences

- No opening hours are stated: none are stored per location.
- A breadcrumb crumb without a link is left out of the list unless it is the last one.
- A new page type gets its node by pushing onto `Controller::$structuredData`.
