feat(web): serve top-level docs publicly at /docs (BUNYIP-385) #379

Merged
nrupard merged 3 commits from feat/BUNYIP-385-docs-route into main 2026-07-20 22:29:56 +02:00
Owner

Summary

Adds a public /docs to bunyip-web (BUNYIP-385): an index at /docs and a per-doc page at /docs/{slug} that renders markdown to HTML. Temporary home for the docs until the dedicated docs app matures.

Decisions (from standup)

  • Scope: top-level docs/*.md only; docs/dev-docs/ internal notes excluded.
  • Access: public (unauthenticated, like /pricing).

How

  • Markdown embedded from bunyip-web/src/docs/*.md - crate-local copies of the top-level docs/*.md (canonical source stays the repo docs/; re-sync on change). Crate-local sidesteps the .dockerignore exclusion of the repo-root docs/ and keeps the OCI build context-independent.
  • Rendered with pulldown-cmark + a small scoped CSS block (bunyip-web has no Tailwind typography plugin).
  • Unknown slug returns 404.

Docs subdomain

The issue assumes the docs subdomain already terminates at Bunyip, so there's no app-side subdomain logic - /docs is served on any domain routed to bunyip-web. If a dedicated docs.<tld> Traefik router is wanted, it belongs in the docker repo (not added here); worth confirming it exists to satisfy the "reachable on the docs subdomain" AC.

Migration

When the dedicated docs app lands, repoint /docs (or 301) and delete this module + the embedded copies.

Verified

fmt + clippy -D warnings + build + new docs_tests (registry soundness + markdown render) green in the pinned rust-builder.

#BUNYIP-385

## Summary Adds a public **/docs** to bunyip-web (BUNYIP-385): an index at `/docs` and a per-doc page at `/docs/{slug}` that renders markdown to HTML. Temporary home for the docs until the dedicated docs app matures. ## Decisions (from standup) - **Scope**: top-level `docs/*.md` only; `docs/dev-docs/` internal notes excluded. - **Access**: public (unauthenticated, like `/pricing`). ## How - Markdown embedded from `bunyip-web/src/docs/*.md` - crate-local **copies** of the top-level `docs/*.md` (canonical source stays the repo `docs/`; re-sync on change). Crate-local sidesteps the `.dockerignore` exclusion of the repo-root `docs/` and keeps the OCI build context-independent. - Rendered with `pulldown-cmark` + a small scoped CSS block (bunyip-web has no Tailwind typography plugin). - Unknown slug returns 404. ## Docs subdomain The issue assumes the docs subdomain already terminates at Bunyip, so there's no app-side subdomain logic - `/docs` is served on any domain routed to bunyip-web. If a dedicated `docs.<tld>` Traefik router is wanted, it belongs in the docker repo (not added here); worth confirming it exists to satisfy the "reachable on the docs subdomain" AC. ## Migration When the dedicated docs app lands, repoint `/docs` (or 301) and delete this module + the embedded copies. ## Verified fmt + clippy `-D warnings` + build + new `docs_tests` (registry soundness + markdown render) green in the pinned rust-builder. #BUNYIP-385
feat(web): serve top-level docs publicly at /docs (BUNYIP-385)
Some checks failed
E2E / Playwright against deployment (pull_request) Successful in 36s
Check / fmt + clippy + build + tests (pull_request) Has been cancelled
78919d0ec4
Adds a public /docs to bunyip-web: an index (/docs) of the top-level repo docs plus a per-doc page (/docs/{slug}) that renders the markdown to HTML. This is the temporary home decided at standup, until the dedicated docs app matures.

Scope is the top-level docs/*.md only; the docs/dev-docs/ internal notes are excluded. The markdown is embedded from bunyip-web/src/docs/*.md, which are crate-local COPIES of the top-level docs/*.md (canonical source is the repo docs/; re-sync the copies when those change). Embedding crate-local sidesteps the .dockerignore exclusion of the repo-root docs/ and keeps the build context-independent. Rendered with pulldown-cmark plus a small scoped CSS block, since bunyip-web has no Tailwind typography plugin. Public (unauthenticated, like /pricing and /our-story) per the chosen access level.

Docs-subdomain note: the issue assumes the docs subdomain already terminates at Bunyip, so no app-side subdomain logic is needed; /docs is served on any domain routed to bunyip-web. A dedicated docs.<tld> Traefik router, if wanted, belongs in the docker repo (not added here). Migration path: when the dedicated docs app lands, repoint /docs (or 301) and delete this module plus the embedded copies.

Verified green (fmt + clippy -D warnings + build + the new docs_tests covering registry soundness and markdown rendering) in the pinned rust-builder.

#BUNYIP-385

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
fix(web): use axum 0.7 colon route param for /docs/:slug (BUNYIP-385)
All checks were successful
E2E / Playwright against deployment (pull_request) Successful in 1m15s
Check / fmt + clippy + build + tests (pull_request) Successful in 19m50s
9247577040
The docs page route was written with axum 0.8 brace syntax (/docs/{slug}); bunyip-web is on axum 0.7, where that is a literal path segment and the Path<String> extractor fails at runtime. Switch to the colon form (/docs/:slug) that every other route here uses. Caught before merge - the build compiled either way since the path is just a string.

#BUNYIP-385

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
fix(web): strip raw HTML from rendered docs for defense-in-depth (BUNYIP-385)
All checks were successful
E2E / Playwright against deployment (pull_request) Successful in 53s
Check / fmt + clippy + build + tests (pull_request) Successful in 44m26s
Create release / Create release from merged PR (pull_request) Has been skipped
80b110e50e
Follow-up to the code review. pulldown-cmark passes raw HTML in the markdown through verbatim, and docs_page splices the result with PreEscaped onto a public page, so a doc could otherwise inject live HTML (e.g. a <script> in a runbook). render_markdown now drops the raw Html / InlineHtml events, leaving only markdown-derived HTML, which push_html escapes correctly. The embedded docs contain no raw HTML today, so this is lossless.

Adds a test asserting block + inline raw HTML are dropped while surrounding text survives. Green: fmt + clippy -D warnings + the docs tests.

#BUNYIP-385

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
nrupard deleted branch feat/BUNYIP-385-docs-route 2026-07-20 22:29:57 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/bunyip!379
No description provided.