← Galaxy / notesorg-wide / engineering-apps-docs-readme

@galaxy/docs — the galaxy-docs reading site

engineering-apps-docs-readme · in engineering/apps/docs · org-wide · updated 2026-06-01 10:19

Frontmatter

lang
en
imported_at
2026-06-01T10:19:40.086Z
source_path
productgalaxy/apps/docs/README.md
source_repo
productgalaxy

@galaxy/docs — the galaxy-docs reading site

Astro 6 + Starlight + Tailwind 4 public READING surface for the 5th product (galaxy-docs). Fetches notes from Galaxy's /api/v1/notes at request time via Astro 6 live content collections, with a build-time snapshot for fast first paint.

  • Authoring happens in the Galaxy admin UI at /admin/notes/ (Next.js, owned by the Phase 4.5 agent).
  • Reading happens here, at docs.galaxy.example.com.
  • Vault export / import for Obsidian round-trip is owned by the Phase 4.6 agent.

This app is server-rendered (output: 'server', Node adapter). Live content collections + Caddy/Cloudflare cache headers give us ISR-style behavior — fresh on edit, snappy on repeat hits.


Quick start (local)

# From the monorepo root:
cp apps/docs/.env.example apps/docs/.env
# Then edit apps/docs/.env to set GALAXY_API_URL + GALAXY_DOCS_API_TOKEN.

pnpm install
pnpm --filter @galaxy/docs dev
# → http://localhost:4321

To point at the staging Galaxy API without running a local Galaxy:

# In apps/docs/.env:
GALAXY_API_URL=https://staging-api.galaxy.example.com
GALAXY_DOCS_API_TOKEN=<bearer-jwt-from-the-staging-galaxy-docs-site-oauth-client>

The token is a short-lived JWT issued by the galaxy-docs-site OAuth client (Client Credentials Flow). Refresh every 15 min — the loader handles refresh automatically when given a refresh token in a future iteration. For now, generate a fresh token before each long dev session:

curl -sX POST $GALAXY_API_URL/oauth/token \
  -d 'grant_type=client_credentials' \
  -d "client_id=galaxy-docs-site" \
  -d "client_secret=$GALAXY_DOCS_SITE_CLIENT_SECRET" \
  | jq -r .access_token

Build & preview

pnpm --filter @galaxy/docs build      # → apps/docs/dist/
pnpm --filter @galaxy/docs preview    # → http://localhost:4321 (production preview)

The build snapshots up to GALAXY_DOCS_BUILD_SNAPSHOT_LIMIT (default 500) notes into a build-time index that pages can consult without a network round-trip. Live content collections handle everything else at request time.

If Galaxy is unreachable at build time, the snapshot is skipped (logged warning, no error). The site still serves correctly — it just falls back to live fetches for everything.


Deploy via docker-compose

The docs service is declared in /Users/parhumm/Projects/SabaIdea/productgalaxy/docker-compose.yml. Image build is multi-stage from apps/docs/Dockerfile.

# Build + bring up the docs container (plus its app + postgres dependencies):
docker compose build docs
docker compose up -d docs

# Tail logs:
docker compose logs -f docs

# Restart after env change (Compose picks up .env changes automatically):
docker compose up -d --force-recreate docs

Production deploys go through Haloy CLI (/Users/parhumm/Projects/SabaIdea/productgalaxy/CLAUDE.md §15: "Zero-downtime deploys via Haloy CLI (layer-only image push + atomic swap)"). Do NOT use docker compose up directly in production.


Layout

apps/docs/
├── astro.config.mjs              # Astro 6 + Starlight + Tailwind 4 + sitemap, SSR
├── astro.starlight.config.ts     # Starlight options (sidebar, i18n, pagefind)
├── tailwind.config.mjs           # Tailwind 4 minimal config (tokens live in CSS)
├── tsconfig.json
├── env.d.ts
├── package.json
├── Dockerfile                    # multi-stage build
├── .env.example
├── README.md                     # ← you are here
└── src/
    ├── live.config.ts            # Astro 6 LIVE content collection (request-time)
    ├── content.config.ts         # Build-time snapshot collection
    ├── middleware.ts             # Loads businesses + active-business cookie
    ├── loaders/
    │   ├── galaxy.ts             # Axios HTTP client (retry, RFC 9457, typed wrappers)
    │   └── sidebar-plugin.ts     # Starlight plugin: API-driven sidebar tree
    ├── components/
    │   ├── Backlinks.astro       # SSR backlinks panel
    │   └── WikilinkRenderer.astro# Renders content_html_cache + cross-domain links
    ├── pages/
    │   ├── index.astro                          # Home: recent + folders + tags + search
    │   ├── health.ts                            # /health liveness probe
    │   ├── api/
    │   │   ├── business-switcher.ts             # POST cookie-set
    │   │   └── search.ts                        # GET → /api/v1/notes/search proxy
    │   └── [business]/
    │       ├── index.astro                      # Per-business landing
    │       ├── [...slug].astro                  # Per-note view (title + body + backlinks)
    │       ├── folder/[...folder].astro         # Folder index view
    │       └── tag/[tag].astro                  # Tag index view
    ├── styles/
    │   └── global.css            # Tailwind 4 import + Starlight token overrides + RTL
    └── content/
        └── static/welcome.md     # Curated in-repo page (survives Galaxy outage)

Operator FAQ

The sidebar is empty / says "businesses fetch failed". The galaxy-docs-site OAuth client either isn't issued yet or lacks businesses:read scope. Re-issue via Galaxy admin → OAuth clients → rotate.

Persian (fa) notes show in the wrong direction. Ensure frontmatter.lang: fa is set on the note. The reader uses frontmatter.lang (NOT a separate column) to flip dir="rtl".

Wikilink [[issue:TVK-AI-008]] is not clickable. Check that PUBLIC_PRODUCT_AUDITS_URL is set in .env. The reader rewrites the cross-domain placeholder href to that target.

Search returns 0 hits for a recently-added note. Pagefind indexes only the build-time snapshot. For live notes, the search box falls back to /api/search (which proxies /api/v1/notes/search). Confirm the endpoint is reachable: curl $GALAXY_API_URL/api/v1/notes/search?q=hello -H "Authorization: Bearer …".

I edited a note in admin but the docs site still shows the old version. Live content cache TTL is 60s by default (GALAXY_DOCS_CACHE_TTL). Hit refresh after the TTL or set GALAXY_DOCS_CACHE_TTL=0 for instant updates during edit sessions.


  • Plan: /Users/parhumm/.claude/plans/now-plan-to-new-spicy-dragonfly.md § "2. Reading surface — dedicated docs site apps/docs/".
  • Research: /Users/parhumm/Projects/SabaIdea/productgalaxy/jaan-to/outputs/pm-research/docs-research.md.
  • Architecture: /Users/parhumm/Projects/SabaIdea/productgalaxy/docs/architecture/ADR-003-batch-3-stack-lockin.md.
  • Docs cache (libraries used here):
    • jaan-to/outputs/docs-cache/astro-6/
    • jaan-to/outputs/docs-cache/astro-live-content-collections/
    • jaan-to/outputs/docs-cache/starlight/
    • jaan-to/outputs/docs-cache/portaljs-remark-wiki-link/

Outbound links (0)

This note doesn't reference any other entity.

Version history (1)

  • v12026-06-01 10:19"galaxy-docs importer: initial import"