Wiki Implementation Guide
Overview
This document describes the implementation of GitHub Issue #180: hosting the project documentation as a private, web-browsable wiki using Google Cloud Storage (GCS) and Docusaurus.
Architecture
Components
-
Docusaurus Static Site Generator
- Modern documentation framework
- Automatic sidebar generation from folder structure
- Local Search functionality (@easyops-cn/docusaurus-search-local)
- Beautiful, responsive UI
-
Firebase Hosting
- Project:
construction-code-expert-dev(Wiki Target) - Static website hosting
- Firebase Authentication (Google Auth Integration)
- Identity Aware Proxy / Allowlist logic handled by App
- Project:
-
Git Hooks
- Post-commit hook triggers on docs changes
- Automatically syncs docs to wiki directory
Data Flow
Developer edits docs/ git commit triggers post-commit hook
↓ ↓
docs/*.md rsync to wiki/docs/
↓ ↓
Commit Docusaurus build (generates search index)
↓ ↓
Post-commit hook wiki/dist/
↓ ↓
deploy-to-firebase-smart.sh firebase deploy
↓ ↓
wiki/docs/ Firebase Hosting (Target: wiki)
↓
Web access via Firebase Auth
↓
https://construction-code-expert-dev-wiki.web.app/
Implementation Files
Scripts
All scripts are located in cli/sdlc/wiki/:
-
init-docusaurus.sh- One-time setup script
- Creates Docusaurus project in
wiki/directory
-
deploy-to-firebase-smart.sh- Smart Build: Checks timestamps to avoid rebuilding unchanged docs
- Build: Runs
npm run build(generates static HTML + Search Index) - Deploy: Deploys
dist/to Firebase Hosting targetwiki
-
sync-docs-to-wiki.sh- Syncs
docs/towiki/docs/using rsync - Handles MDX auto-escaping
- Syncs
Git Hook
.git/hooks/post-commit
- Triggers after every commit
- Detects changes in
docs/folder - Calls
sync-docs-to-wiki.shautomatically - Provides user feedback
Configuration Files
.gitignore: Excludes wiki build artifacts and node_moduleswiki/docusaurus.config.ts: Main config, includes@easyops-cn/docusaurus-search-localplugin.wiki/firebase.json: Hosting configuration (redirects, headers).docs/wiki-implementation.md: This document
Setup Instructions
Prerequisites
# Ensure you have the required tools
node --version # Node.js 18+
npm --version # npm 9+
gcloud version # Google Cloud SDK
# Authenticate with GCP
gcloud auth application-default login
gcloud config set project construction-code-expert-dev
One-Time Setup
# 1. Initialize Docusaurus
./cli/sdlc/wiki/init-docusaurus.sh
# 2. Login to Firebase
firebase login
Daily Usage
# Edit documentation
vim docs/some-doc.md
# Commit changes (triggers automatic sync)
git add docs/
git commit -m "Update documentation"
# Deploy to GCS when ready
./cli/sdlc/wiki/deploy-to-gcs.sh
Deployment
# Smart deploy (builds only if needed)
./cli/sdlc/wiki/deploy-to-firebase-smart.sh
Access Control
The wiki is protected by Firebase Authentication on the main application domain. The Hosting rules require a valid session to access the content if integrated with the main app's routing, or via Cloud Run proxy depending on the specific setup.
Search Implementation
We use @easyops-cn/docusaurus-search-local for search functionality.
- Type: Client-side (Offline) Search
- Index: Built at compile time (
search-index.jsonindist/) - Privacy: 100% Private. The index never leaves the hosting environment and is protected by the same auth as the docs.
Configuration
Managed in wiki/docusaurus.config.ts:
themes: [
[
require.resolve("@easyops-cn/docusaurus-search-local"),
({
hashed: true,
language: ["en"],
docsRouteBasePath: "/",
indexBlog: false,
}),
],
]
Technical Details
GCS Configuration
The bucket is configured with:
- Uniform bucket-level access: Enabled (required for IAM)
- Main page:
index.html - Error page:
404.html - CORS: Allows GET/HEAD from any origin
- Cache-Control:
- Static assets: 1 year
- HTML files: 1 hour
Docusaurus Configuration
Key settings in wiki/docusaurus.config.ts:
- Base URL:
/construction-code-expert-dev-wiki/ - URL:
https://storage.googleapis.com - Docs route: Root path (
/) - Blog: Disabled
- Theme: Classic preset with Material design
- Search: Built-in
Git Hook Behavior
The post-commit hook:
- Runs after every commit
- Checks
git diff-treefor changed files - If any file starts with
docs/, triggers sync - Does NOT automatically deploy to GCS (manual step)
- Provides informative console output
MDX Compatibility and Auto‑Escaping
Docusaurus v3 treats all .md files as MDX. Certain patterns that are harmless in plain Markdown can break MDX parsing or execute as JavaScript during static site generation. To keep source docs clean and avoid manual edits, the sync pipeline auto‑escapes MDX‑sensitive syntax.
What is MDX?
MDX is “Markdown + JSX.” It lets you embed React components and JavaScript expressions inside Markdown. Because MDX parses {}, <>, and other symbols as code, content like ${VAR} or <1s in plain Markdown can be misinterpreted at build time unless escaped or fenced. See the MDX docs for details: mdxjs.com.
What is JSX?
JSX is a JavaScript syntax extension used by React. It lets you write UI using HTML‑like tags that compile to React.createElement(...) calls. Example: <Button size="sm">Click</Button> is valid JSX. In MDX, JSX is allowed inline, so text that looks like a tag (for example <1s, <note>, or <foo>bar) may be parsed as JSX unless it’s escaped or fenced as code.
What does “fenced” mean?
Wrapped as code (inline backticks or triple‑backtick code blocks) so MDX doesn’t parse it as JSX/JS.
What can break MDX:
${variable}outside code blocks (interpreted as JS interpolation)<1s,<2s,>1soutside code blocks (interpreted as JSX)- JSON keys that MDX may misinterpret (e.g., keys with underscores) when content isn’t fenced
What the sync does automatically (cli/sdlc/wiki/escape-mdx-syntax.py):
- Inside code fences:
- Escapes
${to\${}so template literals display literally - Escapes underscores in JSON keys:
"project_id"→"project\_id"
- Escapes
- Outside code fences:
- Escapes
${and additionally wraps any${...}or\${...}in inline code to prevent MDX evaluation, e.g.projects/${project_id}/→projects/`$\{project_id\}`/
- Neutralizes angle‑bracket comparisons before numbers:
<1→`<`1and>1→`>`1
- Escapes
How it runs:
- The escaping script is invoked automatically by
cli/sdlc/wiki/sync-docs-to-wiki.shafterrsynccopiesdocs/intowiki/docs/. - No changes are made to files under
docs/; only the synced copies inwiki/docs/are rewritten for MDX safety.
Validate locally:
# Re‑sync (applies auto‑escaping), then build
./cli/sdlc/wiki/sync-docs-to-wiki.sh
cd wiki && rm -rf .docusaurus dist && npm run build
# Spot‑check transformed lines (example paths)
sed -n '880,912p' wiki/docs/developer-playbooks/playbook.md
Tips when editing docs:
- Prefer fenced code blocks for JSON and shell examples; MDX will leave fenced content alone (we still escape as defense‑in‑depth)
- If you must use
${...}in narrative text, wrap it in inline code:`$\{name\}` - If comparisons like
<1sappear in tables or prose, wrap the<or>in backticks:`<`1s/`>`1s
Advantages of This Approach
- Private by Default: IAM authentication, no public access
- Version Controlled: Docs are part of the repo
- No External Dependencies: Uses existing GCP infrastructure
- Cost Effective: GCS storage and bandwidth costs are minimal
- Automatic Sync: Git hooks keep wiki in sync with docs
- Beautiful UI: Docusaurus provides modern, searchable documentation
- No Additional Hosting: Uses GCP services already in use
Comparison with Alternatives
vs. GitHub Pages
- ❌ GitHub Pages requires Enterprise for private access ($20+/user/month)
- ✅ GCS uses existing GCP IAM, no additional cost
vs. Firebase Hosting
- ❌ Firebase requires separate authentication setup
- ✅ GCS uses existing GCP authentication
vs. Self-Hosted Server
- ❌ Requires server maintenance, security updates
- ✅ GCS is fully managed, highly available
Troubleshooting
Git Hook Not Running
# Make hook executable
chmod +x .git/hooks/post-commit
# Test manually
.git/hooks/post-commit
Permission Denied Errors
# Re-authenticate
gcloud auth application-default login
gcloud config set project construction-code-expert-dev
# Verify bucket permissions
gsutil iam get gs://construction-code-expert-dev-wiki
Build Errors
cd wiki
rm -rf node_modules package-lock.json .docusaurus
npm install
npm run build
Sync Issues
# Manual sync
./cli/sdlc/wiki/sync-docs-to-wiki.sh
# Check rsync output
rsync -av --delete --dry-run docs/ wiki/docs/
Maintenance
Updating Docusaurus
cd wiki
npm update
npm audit fix
git commit -am "Update Docusaurus dependencies"
Backup Strategy
The wiki content is backed up in multiple places:
- Source docs in git repository (primary source)
- GCS bucket (deployed version)
- Local wiki/docs directory (synced copy)
Monitoring
Monitor GCS bucket usage:
# Check bucket size
gsutil du -sh gs://construction-code-expert-dev-wiki
# Check access logs (if enabled)
gsutil ls gs://construction-code-expert-dev-wiki-logs/
Future Enhancements
Potential Improvements
- CI/CD Integration: GitHub Actions to auto-deploy on merge to main
- Custom Domain: Map to custom domain
- Analytics: Add Google Analytics
- Versioning: Add version selector
- Automated Testing: Add link checker
CI/CD Example (Future)
# .github/workflows/deploy-wiki.yml
name: Deploy Wiki
on:
push:
branches: [main]
paths: ['docs/**']
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: google-github-actions/setup-gcloud@v0
- run: ./cli/sdlc/wiki/sync-docs-to-wiki.sh --deploy
Related Documentation
Support
For questions or issues:
- Check the QUICKSTART.md in the
cli/sdlc/wiki/directory - Review the README.md in the
cli/sdlc/wiki/directory - Check troubleshooting section above
- Open an issue on GitHub