# Schema / Structured Data Audit — Quire Guide (quire.io/guide/)

Audited via source inspection of the Jekyll build pipeline (`_includes/_seo.html`, `_includes/head.html`,
`_includes/faq_schema.html`, `_plugins/faq_schema_plugin.rb`, `_layouts/single.html`) and the rendered
output in `_site/` (e.g. `_site/index.html`, `_site/add-task/index.html`), cross-checked against a sample
of `_docs/en/*.md` source pages. 139 English guide pages were scanned programmatically for FAQ
frontmatter/visible-content parity; individual pages were spot-checked for full JSON-LD validity.

## Detection Results

### 1. WebSite + Organization (`@graph`, injected via `_includes/_seo.html` on every page)

```json
{
  "@context": "https://schema.org",
  "@graph": [
    { "@type": "WebSite", "@id": "{{ site.url }}{{ site.baseUrl }}#website", ... },
    { "@type": "Organization", "@id": "{{ site.url }}#organization", ... }
  ]
}
```

Rendered output (e.g. on `/add-task/` and on the guide root `/`):

```json
"@type": "WebSite",
"@id": "http://0.0.0.0:4000#website",
"url": "http://0.0.0.0:4000"
```

(in production this resolves to `https://quire.io#website` / `https://quire.io`, **not**
`https://quire.io/guide#website`).

**Root cause:** `_includes/_seo.html` references `site.baseUrl` (capital U), but `_config.yml` defines
`baseurl: "/guide"` (lowercase). Liquid is case-sensitive, so `site.baseUrl` always resolves to `nil` and
silently drops the `/guide` segment from both the `WebSite.@id` and `WebSite.url`. This bug is present on
every single page across all 14 locales.

Organization block itself (name, `sameAs`, `contactPoint`, `founder`, `parentOrganization`,
`foundingDate`) is well-formed and uses absolute URLs throughout.

### 2. FAQPage (dynamically generated, `_plugins/faq_schema_plugin.rb` → `_includes/faq_schema.html`)

- Architecture: a Jekyll `Generator` reads the frontmatter `faq:` array on any doc/post and compiles it
  into a `FAQPage` JSON-LD object at build time (single source of truth — no manual duplication).
- Confirmed present on all 139 sampled English pages, correctly gated (`{%- if page.faq_schema -%}`) so
  pages without a `faq:` block emit no schema.
- Structurally valid: `@context: https://schema.org`, `@type: FAQPage`, `mainEntity[].{@type: Question,
  name, acceptedAnswer.{@type: Answer, text}}`, correct BCP-47 `inLanguage` per locale, no placeholder
  text, JSON is well-formed (verified via rendered `_site/add-task/index.html`).

### 3. Article / CreativeWork (Microdata, `_layouts/single.html`)

```html
<article class="page" itemscope itemtype="https://schema.org/CreativeWork">
  <meta itemprop="headline" content="...">
  <meta itemprop="description" content="...">
  <meta itemprop="datePublished" content="August 23, 2019">
  <meta itemprop="dateModified" content="...">
  <section itemprop="text">...</section>
```

- Uses Microdata, not JSON-LD (inconsistent with the JSON-LD used elsewhere on the same page).
- `@type` is generic `CreativeWork`, not `Article`/`TechArticle`.
- `datePublished`/`dateModified` are formatted `"%B %d, %Y"` (e.g. "August 23, 2019"), not ISO 8601.
- Missing `author`, `publisher`, `image`, `mainEntityOfPage` — required/recommended properties for
  Article-family types.

### 4. BreadcrumbList — not implemented (dead code path)

`_layouts/single.html` contains:

```liquid
{%- if page.url != "/" and site.breadcrumbs -%}
  {%- unless paginator -%}
    {%- include breadcrumbs.html -%}
  {%- endunless -%}
{%- endif -%}
```

- `site.breadcrumbs` is never set in `_config.yml`, so this block never executes.
- `_includes/breadcrumbs.html` does not exist in the repo at all — if `site.breadcrumbs` were ever set
  to `true`, the build would fail on a missing include.
- No `BreadcrumbList` JSON-LD or visible breadcrumb nav is emitted anywhere in `_site/`.

### 5. Deprecated / retired types

- No `HowTo`, `SpecialAnnouncement`, `CourseInfo`, `EstimatedSalary`, or `LearningVideo` schema found
  anywhere in `_includes`, `_layouts`, or `_plugins`. Clean.
- Per project record, `HowTo` schema work was already reviewed and is implementation-ready but
  intentionally on hold pending AI-citation round-3 data collection — **not** re-flagged here as a new
  recommendation; no action needed until that decision is revisited.

## Validation Results

| Block | @context | @type valid | Required props | No placeholders | Absolute URLs | ISO 8601 dates | Verdict |
|---|---|---|---|---|---|---|---|
| WebSite | ✅ https | ✅ | ⚠️ `url`/`@id` truncated by baseUrl bug | ✅ | ⚠️ URL missing `/guide` | n/a | **FAIL** (bug) |
| Organization | ✅ https | ✅ | ✅ | ✅ | ✅ | n/a | PASS |
| FAQPage | ✅ https | ✅ (but no SERP benefit per Google policy) | ✅ | ✅ | n/a | n/a | PASS (structurally); see content-drift note below |
| CreativeWork (Microdata) | n/a (Microdata) | ⚠️ too generic, should be Article/TechArticle | ❌ missing author/publisher/image/mainEntityOfPage | ✅ | n/a | ❌ non-ISO date format | **FAIL** |
| BreadcrumbList | — | — | — | — | — | — | **Not implemented** |

### FAQPage content-drift check (frontmatter `faq:` vs. visible "Frequently Asked Questions" section)

Programmatically compared question counts and question text across all 139 English `_docs` pages
(frontmatter is the schema source of truth per the Jekyll generator).

- 139/139 pages have both a frontmatter `faq:` block and a visible FAQ section (no pages are missing
  one or the other).
- 8/139 pages (~6%) show a genuine mismatch in question count between the schema source and the visible
  section, beyond the expected "shorter visible answer, longer SEO answer" rewording pattern described in
  `GUIDE-FORMAT.md`. Example — `billing-01-master-organization.md`: frontmatter (11 questions) includes
  "What is a Master Organization in Quire?", "Which Quire plans support Master Organization and what can
  be linked?", "Who can link or unlink organizations to a Master Organization?", and "How does Master
  Access differ from Global Access in Quire?" — none of which appear in the visible FAQ (9 questions),
  which instead asks "Can I link paid organizations to a Master Organization?" and "Is the Master
  Organization feature available on all plans?", not present in the schema. This is not just reworded
  phrasing — it's a different question set, meaning `FAQPage` markup asserts the page answers questions
  it doesn't visibly answer, and vice versa.
  - Other pages with the same pattern: `timetracking-01-time-tracking-timer.md` (8 vs 9),
    `mobile-03-mobile-app-task.md` (8 vs 7), `tasklistad-06-approval.md` (7 vs 8),
    `overview-07-mobile-apps.md` (8 vs 7), `document-01-documents.md` (11 vs 10),
    `tasklistad-09-get-notified.md` (11 vs 9), `charts-01-charts.md` (10 vs 9).
- The remaining ~131 pages initially flagged by a naive `####`-count scan were false positives caused by
  unrelated `####` headings elsewhere in the body (e.g. formula/function reference lists); after scoping
  the count to text following "Frequently Asked Questions," only the 8 pages above are real mismatches.

## Missing Schema Opportunities

1. **Fix the `site.baseUrl` typo** so `WebSite.@id`/`WebSite.url` correctly resolve to
   `https://quire.io/guide#website` / `https://quire.io/guide`, distinct from the main marketing site's
   own entity graph.
2. **BreadcrumbList** — the guide is deeply category-nested (e.g. Tasks → Add Tasks & Subtasks) across 14
   locales; implement real `BreadcrumbList` JSON-LD (the current `site.breadcrumbs`/`breadcrumbs.html`
   scaffold is inert and the include is missing).
3. **Article/TechArticle in JSON-LD** — replace or supplement the `CreativeWork` Microdata with a proper
   JSON-LD `TechArticle` (better fit than generic `Article` for product-documentation content), including
   `author`, `publisher`, `image`, `mainEntityOfPage`, and ISO 8601 `datePublished`/`dateModified`.
4. Reconcile the 8 pages where `faq:` frontmatter and the visible FAQ section ask different questions.

## Generated JSON-LD for Recommended Additions

### BreadcrumbList (add as new `_includes/breadcrumbs.html`, JSON-LD variant, alongside/instead of the
dead visible-breadcrumb scaffold)

```html
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {
      "@type": "ListItem",
      "position": 1,
      "name": "Guide",
      "item": "https://quire.io/guide/"
    },
    {
      "@type": "ListItem",
      "position": 2,
      "name": "{{ page.title | markdownify | strip_html | strip_newlines | escape_once }}",
      "item": "https://quire.io{{ page.url }}"
    }
  ]
}
</script>
```

(Expand to reflect actual category depth if/when a category-index level is introduced between the guide
root and individual articles.)

### TechArticle (JSON-LD, replacing/supplementing the CreativeWork Microdata in `_layouts/single.html`)

```html
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "TechArticle",
  "headline": "{{ page.title | markdownify | strip_html | strip_newlines | escape_once }}",
  "description": "{{ page.excerpt | markdownify | strip_html | strip_newlines | escape_once }}",
  "datePublished": "{{ page.date | date_to_xmlschema }}",
  "dateModified": "{{ page.last_modified_at | date_to_xmlschema }}",
  "inLanguage": "{{ in_language }}",
  "author": {
    "@type": "Organization",
    "name": "Quire"
  },
  "publisher": {
    "@type": "Organization",
    "name": "Quire",
    "logo": {
      "@type": "ImageObject",
      "url": "https://d12y7sg0iam4lc.cloudfront.net/img/logo_trans_1200.png"
    }
  },
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "https://quire.io{{ page.url }}"
  }
}
</script>
```

### Corrected WebSite entity (fix for `_includes/_seo.html`)

```json
{
  "@type": "WebSite",
  "@id": "{{ site.url }}{{ site.baseurl }}#website",
  "url": "{{ site.url }}{{ site.baseurl }}",
  "name": {{ site.name | jsonify }},
  "description": {{ site.description | jsonify }},
  "inLanguage": {{ in_language | jsonify }}
}
```

(Only the casing of `baseurl` changes — `baseUrl` → `baseurl` — to match the variable actually defined in
`_config.yml`.)
