Oracle Setup¶
Problem¶
Documentation is scattered across multiple GitHub repositories. It's difficult to find docs, there's no unified search, and API documentation is hard to discover.
Taking inspiration from Backstage proposal in Tech Proposal.
Solution¶
A static documentation portal using MkDocs that aggregates docs from multiple repos.
Why not Backstage?¶
Backstage is a full internal developer platform (service catalog, infrastructure tooling, workflows), not just a documentation portal, so it's much heavier than what we need. Since our goal is just multi-repo docs with search and PR-based editing, a MkDocs-based static portal is much simpler and faster to build.
Architecture¶
GitHub Actions (scheduled every 30min)
↓
Clone repos → Copy docs + OpenAPI specs → Build MkDocs → Deploy
↓
Static Site on Cloudflare Pages (behind Cloudflare Access)
Stack¶
| Component | Choice | Rationale |
|---|---|---|
| Static site generator | MkDocs + Material theme | Simple, fast, built-in search, beautiful |
| Repo access | GitHub App (read-only) | Secure access to private repos |
| Build automation | GitHub Actions | Scheduled builds, no webhooks |
| Search | MkDocs built-in | Client-side, no backend needed |
| Hosting | Cloudflare Pages | Free, CDN, built-in basic auth |
| Authentication | Cloudflare Access (One-Time PIN) | Simple email-based access, no auth server needed |
| API docs | Swagger UI (embedded) | Interactive, static |
| Edit workflow | GitHub's native editor | Link to github.com/.../edit/... |
| Configuration | repos.yml | Version-controlled, no database |
Out of Scope (For Now)¶
Not building the below initially, but can add later if needed:
- Backend server / database: Add if we need fine-grained permissions or custom workflows
- Custom search engine (Meilisearch): Add if MkDocs search becomes too slow
- Webhooks: Add if 30-min delay becomes unacceptable
- Custom editor: Add if need edit-in-place functionality
- Expose for LLMs: The same documentation can serve LLMs (Claude Code, Cursor, etc.). Since MkDocs already produces structured markdown files, we can expose them via an MCP server for coding assistants to consume.
How It Works¶
Build Process¶
GitHub Actions runs every 30 minutes:
- Read
repos.ymlfor list of repos - Clone/pull each repo into
_repos/{name}/ - Copy docs to
docs/{repo-name}/based ondocs_path,docs_paths, ordocs_pattern - Copy OpenAPI specs to
docs/{output}(e.g.,docs/api/main-api.json) - Inject source metadata into each markdown file (for edit links)
- Run
mkdocs build→ outputs tosite/ - Deploy
site/to Cloudflare Pages
Editing Docs¶
Each page has an "Edit on GitHub" button that links to https://github.com/{org}/{repo}/edit/{branch}/{path}. User edits in GitHub's native editor, creates PR. Next build picks up changes.
Search¶
MkDocs generates search_index.json at build time. Browser loads this JSON and searches client-side using Lunr.js. No backend needed.
API Documentation¶
OpenAPI specs live in the source repos. The fetch script copies them to the portal. Swagger UI is embedded in markdown pages and loads the local JSON spec.
For backend repo owners: To have your API docs appear in the portal:
- Generate an OpenAPI spec file in your repo (e.g.,
openapi.jsonorswagger.yaml) - Add an entry to
repos.ymlin the docs-portal repo pointing to your spec - The portal will automatically fetch and display it with Swagger UI
Repository Structure¶
oracle/
├── .github/workflows/
│ └── build-deploy.yml # CI: scheduled build + deploy to Cloudflare Pages
├── docs/
│ ├── index.md # Portal homepage
│ ├── team-guides/ # Org-level docs (checked into this repo)
│ │ └── pr-guidelines.md
│ ├── backend-api/ # Fetched from backend-api repo
│ ├── frontend-app/ # Fetched from frontend-app repo
│ └── api/ # API doc pages with Swagger UI
├── overrides/
│ └── main.html # Edit on GitHub button customization
├── scripts/
│ └── fetch_repos.py # Clone repos, copy docs, inject frontmatter
├── mkdocs.yml # MkDocs configuration
├── repos.yml # Source repos + API specs config
├── requirements.txt # Python dependencies
└── .gitignore
- Team/org-level docs: Live in
docs/(e.g.,docs/index.md,docs/team-guides/) — version-controlled in this repo - Fetched repo docs: Go into
docs/{repo-name}/— prevents file conflicts, clear ownership per repo
Configuration¶
repos.yml¶
Three ways to specify what to fetch per repo:
docs_path: Single folderdocs_paths: List of foldersdocs_pattern: Glob pattern (e.g.,**/*.mdfor all markdown files)
repos:
- name: backend-api
url: https://github.com/yourorg/backend-api
branch: main
docs_path: docs/ # Single folder
- name: frontend-app
url: https://github.com/yourorg/frontend-app
branch: main
docs_paths: # Multiple folders
- docs/
- guides/
- name: mobile-app
url: https://github.com/yourorg/mobile-app
branch: main
docs_pattern: "**/*.md" # Glob all markdown files
# OpenAPI specs (optional)
openapi_specs:
- name: main-api
repo: backend-api
path: openapi.json
output: api/main-api.json
GitHub App Setup¶
Create a GitHub App with:
- Permissions: Contents (Read), Metadata (Read)
- Webhooks: Disabled (not needed)
- Install on organization, store App ID and private key as GitHub Actions secrets
Authentication¶
Cloudflare Access with One-Time PIN. Add allowed email addresses or an email domain (e.g., *@yourcompany.com). Users get a PIN via email to access the site. Simple, no auth server integration needed.