Skip to content

FAQ multi-version refactor: per-branch data files + main-side site generator #163

@pacphi

Description

@pacphi

Background

The FAQ source (docs/faq/src/v3-faq-data.json, builder docs/faq/build.mjs) was originally written for v3 only. After the April 2026 reorg (PR #150 / #161) it now lives at v3/docs/faq/. Going forward we have multiple maintained generations (v2, v3, v4, …vN) and want a unified FAQ site that draws from all of them.

Goal

A FAQ data file per active version branch, plus a generator that lives on main and aggregates them into one published site — runnable on demand via a workflow.

Proposed design

1. Per-branch data files

Each branch holds only the FAQ entries that apply to its version:

Branch Data file
v2 v2/docs/faq/faq-data.json (new)
v3 v3/docs/faq/faq-data.json (rename from v3-faq-data.json)
v4 v4/docs/faq/faq-data.json (new)

Data shape unchanged ({id, category, question, answer, tags, docs}) plus a per-file implicit version (filename / branch).

If we want a single entry to apply to multiple versions, support applies_to: ["v3","v4"] in each entry — the generator dedupes across branches by id, keeping the highest version by default and merging tags. (Open question — see below.)

2. Main-side generator

Lives at main:.github/scripts/faq/build-aggregate.mjs. It:

  1. For each v* branch in a configurable list:
    • git show origin/<branch>:docs/faq/faq-data.json (or vN/docs/faq/faq-data.json)
    • Parse and tag each entry with its source version
  2. Merge into a single entries[], dedupe by id (keep newest version, log conflicts)
  3. Render through the existing build.mjs template logic — output a single dist/index.html
  4. Emit a JSON manifest of which entries came from which branch (useful for diagnostics)

The HTML template gains a version filter toggle (alongside the existing category filter) so end users can scope the FAQ to a specific version.

3. Trigger workflow

main:.github/workflows/build-faq.yml:

  • workflow_dispatch (manual trigger; inputs: branches list, deploy yes/no)
  • Optional schedule: cron (weekly?)
  • Optional repository_dispatch so a v* CI can ping it after data file changes

Pipeline:

  1. Checkout main
  2. git fetch all v* branches
  3. Run build-aggregate.mjs
  4. Validate output (pnpm --prefix .github/scripts/faq run validate)
  5. If deploy: trueflyctl deploy to https://sindri-faq.fly.dev (the existing site)

4. fly.toml ownership

Currently v3/docs/faq/fly.toml deploys the v3-only site. Move the deployment manifest to main:.github/scripts/faq/fly.toml (since deployment is a main-side concern now). Each v* branch keeps only its own data file + builder template.

Migration steps

  1. Per branch (separate PRs):
    • v3: rename v3/docs/faq/src/v3-faq-data.jsonv3/docs/faq/faq-data.json. Strip site-build tooling that's moving to main.
    • v2: extract v2-applicable entries from current data, place at v2/docs/faq/faq-data.json.
    • v4: seed with a small set of v4-only entries (or copy v3 entries with applies_to and triage later).
  2. Main:
    • Add .github/scripts/faq/{build-aggregate.mjs, fly.toml, Dockerfile, src/index.html, src/faq.js} (template files moved from v3).
    • Add .github/workflows/build-faq.yml.
  3. Cutover:
    • First triggered run validates dedupe behavior.
    • Update https://sindri-faq.fly.dev to point to the aggregated build.
    • Remove old v3-only flyctl deploy route.

Open design questions

  • Cross-version entries: support applies_to: [v3, v4] in the data, or strict per-branch ownership (entry only lives on the branch it applies to, no overlap allowed)?
  • Conflict resolution when the same id appears on multiple branches with different content — fail the build, take the newer branch, or merge with a separator?
  • Schema validation — formalize via JSON Schema in main:.github/scripts/faq/schema/faq-data.schema.json? Currently validate-faq.sh uses simple regex.
  • Search index — current site builds a client-side flexsearch index. With more entries from all versions this stays viable (~few hundred questions), but plan for it.
  • Anonymous v1 entries — v1 is EOL; do we backfill any FAQ for it, or skip?

Non-goals

  • Auto-deploy on every push (manual / scheduled only — keeps fly.io cost predictable).
  • Per-version separate sites (one unified site is the goal).

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions