Skip to content

RFC: Consolidate docs into a single monorepo + modernize the stack (seeking consensus) #5105

@DeepDiver1975

Description

@DeepDiver1975

Summary

This is an RFC to consolidate the 9 documentation repositories into a single monorepo and modernize parts of the build stack, while keeping Antora + AsciiDoc as the core authoring/build tooling.

No work has started. This issue exists to gather consensus before moving on. Please react / comment with agreement, concerns, or alternatives.


Current setup (the problem)

Documentation today spans 9 repos:

  • owncloud/docs — orchestrator: site.yml aggregates content, holds the Antora/AsciiDoc extensions, global-attributes.yml, and the CI that builds + deploys to GitHub Pages (doc.owncloud.com).
  • 7 content reposdocs-main, docs-server, docs-ocis, docs-webui, docs-client-desktop, docs-client-ios-app, docs-client-android. Each is an Antora component with multiple maintained version branches (e.g. master, 10.16, 10.15).
  • owncloud/docs-ui — a Gulp/Browserify/jQuery UI theme published as ui-bundle.zip and pulled in at build time.

Two pains drive this:

  1. Repo + branch sprawl. A single fix can require backports (cherry-picks) across N branches across several repos. Branch protection, commit signing, conventional-commit titles, and CI all multiply per branch/repo.
  2. The tech stack is up for honest re-evaluation — not change for its own sake, but checking whether each piece still earns its place.

Proposed decisions

Area From To
Repos 9 1 monorepo (owncloud/docs); others archived
Branches master + N version branches per repo master only
Versions git branches + backporting folders, real version numbers, prerelease marker
Search Elasticsearch + custom index extension + CI secrets Pagefind (static, build-time)
UI custom Gulp/Browserify/jQuery theme + ui-bundle.zip release stock default UI + small supplemental branding
Content sources 7 remote GitHub repos × branches local folders
Global attributes fetched from GitHub at build local file
Core stack Antora + AsciiDoc kept (tabs / remote-include / Kroki / Mermaid extensions)

Why keep Antora + AsciiDoc

The pain is structural (repos/branches), not the authoring tool. Antora is purpose-built for multi-version, multi-component technical docs (version switcher, cross-component xrefs, latest URL handling), and AsciiDoc is materially more capable than Markdown for our content (includes/partials, conditional content, attributes, admonitions, tables, callouts) — which our content already relies on. A migration to MkDocs/Astro would impose a large, lossy AsciiDoc→Markdown conversion and weaker native versioning to solve a smaller problem than consolidation already removes.

Versioning — no magic next

There is no next folder. Each in-development version uses its real version number with Antora's prerelease key:

# content/ocis/8.1/antora.yml
name: ocis
version: '8.1'
prerelease: true               # marks it unpublished / in development
display_version: '8.1 (dev)'   # optional label in the version switcher

On release: drop prerelease: true (and the (dev) label). No rename, no branch cut, no content move.

Per-product policy:

  • Multi-version (folders): Server/classic, oCIS, desktop, webui.
  • Latest-only (single folder): iOS and Android — app stores carry only one version, docs reflect that.

Backporting is replaced by "edit the folders it applies to." Shared content drift is mitigated with AsciiDoc includes.


Full design spec

Click to expand the complete design document (2026-06-15-owncloud-docs-monorepo-design.md)
# ownCloud Docs — Monorepo Consolidation & Stack Modernization

**Status:** Proposed — awaiting consensus
**Date:** 2026-06-15

## Problem

The ownCloud documentation is spread across 9 repositories:

- `owncloud/docs` — orchestrator: `site.yml` aggregates content, holds the
  Antora/AsciiDoc extensions, `global-attributes.yml`, and the CI that builds
  and deploys to GitHub Pages (`doc.owncloud.com`).
- 7 content repos — `docs-main`, `docs-server`, `docs-ocis`, `docs-webui`,
  `docs-client-desktop`, `docs-client-ios-app`, `docs-client-android`. Each is
  an Antora component with multiple maintained version branches
  (e.g. `master`, `10.16`, `10.15`).
- `owncloud/docs-ui` — a Gulp/Browserify/jQuery-built Antora UI theme published
  as `ui-bundle.zip` and pulled in at build time.

Two pains drive this rework:

1. Repo and branch sprawl. A single fix can require cherry-picks (backports)
   across N branches across several repos. Branch protection, commit signing,
   conventional-commit titles, and CI all multiply per branch/repo.
2. The tech stack is up for genuine re-evaluation — not change for its own
   sake, but an honest check of whether each piece still earns its place.

## Decisions

| Area | From | To |
|------|------|-----|
| Repos | 9 | 1 monorepo (`owncloud/docs`); others archived |
| Branches | `master` + N version branches per repo | `master` only |
| Versions | git branches + backporting | folders, real version numbers, `prerelease` marker |
| Search | Elasticsearch + custom index extension + CI secrets | Pagefind (static, build-time) |
| UI | custom Gulp/Browserify/jQuery theme + `ui-bundle.zip` release | stock default UI + small supplemental branding |
| Content sources | 7 remote GitHub repos × branches | local folders |
| Global attributes | fetched from GitHub at build | local file |
| Core stack | Antora + AsciiDoc | kept (with tabs / remote-include / Kroki / Mermaid extensions) |

### Why keep Antora + AsciiDoc

The pain is structural (repos/branches), not the authoring tool. Antora is
purpose-built for exactly this shape of problem:

- Native multi-version + multi-component support, version switcher,
  cross-component xrefs, and `latest` URL handling — our exact use case.
- AsciiDoc is materially more capable than Markdown for technical docs:
  includes/partials, conditional content (`ifdef`), attributes/variables,
  admonitions, real tables, callouts. The content already leans on these.
- Stable, boring, low-churn tooling.

A migration to MkDocs Material or Astro Starlight would impose a large, lossy
AsciiDoc→Markdown conversion and weaker native versioning, to solve a problem
(contributor familiarity) that is smaller than the structural pain the
consolidation already removes.

## Design

### 1. Repository structure

    docs/
    ├─ site.yml                      # Antora playbook (local content sources only)
    ├─ package.json                  # one toolchain: antora + asciidoctor + extensions
    ├─ antora-extensions/            # ex ext-antora/ (shared, no longer duplicated)
    ├─ asciidoc-extensions/          # ex ext-asciidoc/ (tabs, remote-include)
    ├─ global-attributes.yml         # local file, not fetched from GitHub
    ├─ ui/
    │   └─ supplemental/             # logo, colors, tabs CSS/JS, pagefind widget
    ├─ content/
    │   ├─ main/                     # landing pages (ROOT component)
    │   ├─ server/   {11.0, 10.16, 10.15}/
    │   ├─ ocis/     {8.1, 8.0, 7.3}/
    │   ├─ webui/    {…}/
    │   ├─ desktop/  {7.0, 6.0, 5.3}/
    │   ├─ ios/                      # single version (latest-only)
    │   └─ android/                  # single version (latest-only)
    └─ .github/workflows/ci.yml

Each product is an Antora component; each version folder carries its own
`antora.yml` declaring `version:`. `master` is the only branch.

### 2. Versioning — real version numbers, no magic `next`

There is no `next` folder. Each in-development version uses its real,
known version number with Antora's `prerelease` key:

    # content/ocis/8.1/antora.yml
    name: ocis
    version: '8.1'
    prerelease: true               # marks it unpublished / in development
    display_version: '8.1 (dev)'   # optional label in the version switcher

- Folder named for the actual upcoming version (`8.1`, `11.0`) — no indirection.
- `prerelease: true` keeps it out of the `latest` URL segment and shows a visible
  marker in the version dropdown.
- On release: remove `prerelease: true` (and the `(dev)` label). No rename, no
  branch cut, no content move — it becomes the latest released version.
- This removes the awkward `latest-server-version: 'next@'` soft-set attributes;
  the version key is the source of truth.

Per-product version policy:

- Multi-version (folders): Server/classic, oCIS, desktop, webui.
- Latest-only (single folder): iOS and Android — the app stores carry only
  one version, so the docs reflect that.

Backporting is replaced by "edit the folders it applies to." Day-to-day work
lands in the current prerelease folder (e.g. `ocis/8.1/`); a fix that also applies
to a shipped version is copied into that version's folder in the same PR. Shared
content drift is mitigated with AsciiDoc includes (a shared partial included into
each version folder).

### 3. Build & CI

A single `npm run antora` builds the whole site from local content (no remote
fetches), then Pagefind indexes the output, then it deploys.

    on:
      push: { branches: [master] }
      pull_request:
    jobs:
      build:
        steps:
          - checkout
          - setup-node (22)
          - npm ci
          - npm run antora              # antora site.yml → public/
          - npx pagefind --site public  # inject static search index into public/
          - if push to master → deploy public/ to gh-pages (CNAME doc.owncloud.com)

Changes vs. today:

- No remote content sources. `site.yml` `content.sources` becomes local
  paths instead of seven GitHub URLs × multiple branches. Fully reproducible
  offline; no network flakiness.
- `global-attributes.yml` is local — the GitHub-fetch path in
  `load-global-site-attributes.js` is dropped (extension can be retired and
  folded into `site.yml` `asciidoc.attributes`).
- No Elasticsearch secrets. `generate-index.js` and the four
  `ELASTICSEARCH_*` CI secrets are deleted.
- No `ui-bundle.zip` release dependency. The cross-repo "publish UI release →
  docs build pulls it" handshake disappears.
- PR builds validate the full site (and may run the broken-link check); only
  `master` deploys.

Extensions that remain (they earn their keep) and move into
`antora-extensions/` / `asciidoc-extensions/`, no longer duplicated:
`tabs.js`, `remote-include-processor.js`, Kroki/Mermaid, `comp-version`,
`sitemap-cleanup`.

### 4. Search — Pagefind

- Build-time, post-Antora: `npx pagefind --site public` crawls the generated
  HTML and writes a static, chunked index (`public/pagefind/`). No server, no
  secrets, no index-generation extension.
- UI integration: wire Pagefind's JS API into the stock UI search box
  (small JS + CSS in `ui/supplemental/`).
- Scoping: emit Antora attributes as `data-pagefind-filter` (component, version)
  so search can be scoped to e.g. "oCIS 8.0" or run site-wide.
- Deleted: `@elastic/elasticsearch`, `generate-index.js`, `es-docker-compose.yml`,
  and the four `ELASTICSEARCH_*` secrets.

### 5. UI — supplemental branding on the stock default UI

The custom `docs-ui` repo and its Gulp/Browserify/jQuery build are retired.

- Base: Antora's stock default UI bundle (maintained upstream, no build on
  our side).
- Branding via `supplemental_files`: a small `ui/supplemental/` folder layered
  on at build time — ownCloud logo/favicon, brand-color CSS override, footer text,
  and the few behaviors not in the stock UI: tabs, copy-to-clipboard, and
  the Pagefind search widget.
- Version switcher, mobile nav, breadcrumbs, on-this-page TOC, and anchor
  scrolling are already in the stock UI — the custom JS files
  (`01-nav``07-breadcrumbs`) are dropped.
- `site.yml` points `ui.bundle.url` at the stock default UI release and sets
  `ui.supplemental_files: ./ui/supplemental`.

Trade-off: pixel-level theme control is reduced. Individual stock templates
can still be overridden via supplemental files; a full fork of the default UI
remains a fallback if a future design demands it. For a docs site this is almost
always sufficient.

## Out of scope

- Content rewriting / restructuring beyond moving into version folders.
- PDF generation (already dropped from the current build; can be re-added later).
- Any change to the published URL scheme (`doc.owncloud.com`) beyond what the
  version-folder model implies.

## Migration outline (high level)

1. Create the monorepo skeleton (`content/`, `ui/supplemental/`, extensions).
2. Import each content repo's `master` into `content/<product>/<version>/`, and
   each maintained version branch into its own version folder.
3. Localize `global-attributes.yml`; rewrite `site.yml` content sources to local
   paths; set `prerelease` on in-development versions.
4. Swap search to Pagefind; delete the Elasticsearch extension and secrets.
5. Swap UI to stock default + `ui/supplemental/`; retire `docs-ui`.
6. Rewrite CI to the single build → Pagefind → deploy flow.
7. Verify the built site (version switcher, search, tabs, diagrams, redirects),
   then archive the old repos.

Open questions for reviewers

  • Migration of git history: import each content repo's history into the monorepo (subtree merge) or start clean? History preservation vs. simplicity.
  • Redirects: confirm the version-folder URL scheme preserves existing doc.owncloud.com paths (the static redirect facility should cover renames).
  • Per-product version retention: confirm how many older versions each product (server, oCIS, desktop, webui) keeps as folders.
  • Editor preview: how contributors preview a single component locally without building the whole site.

Please weigh in. 🙏


🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions