Skip to content

feat(docs): docs plugin — velite content pipeline, read-only API + public UI - #450

Open
elliotBraem wants to merge 4 commits into
mainfrom
feat/docs-plugin
Open

elliotBraem wants to merge 4 commits into
mainfrom
feat/docs-plugin

Conversation

@elliotBraem

Copy link
Copy Markdown
Contributor

Closes #444
Implements #445, #446, #447, #448, #449

Summary

The repository's own markdown becomes the product: the new docs plugin compiles docs/** + GLOSSARY.md at build time with Velite and serves it read-only — no database, no secrets, no publishing pipeline. Content truth is git; edits land via merge → CI deploy → recompile.

plugins/docs/
├── velite.config.ts        # content root = repo docs/; slug/title/tags/order schema
├── build.config.ts         # VeliteContentPlugin → rspack beforeCompile hook
├── src/
│   ├── contract.ts         # listPublished (q/tag/limit/cursor) + getBySlug
│   ├── service.ts          # DocsService — pure, fixture-tested
│   └── index.ts            # createPlugin; imports compiled .velite JSON
└── ui/src/routes/
    ├── _public/docs.tsx        # layout (Outlet)
    ├── _public/docs/index.tsx  # /docs index — nav via staticData.nav (book icon)
    └── _public/docs/$.tsx      # splat reader — shared MarkdownRenderer

Enabling change: createPluginBaseConfig gains extraPlugins — the sanctioned escape hatch for build-time integrations (build.config.ts appends rspack plugin instances after the composed defaults).

Design notes: client-side rendering with one shared MarkdownRenderer (react-markdown + shiki JS engine — no WASM in the bundle), so any future draft-editor preview gets parity by construction. Editing, drafts, and a publish/PR pipeline are explicit non-goals (follow-up epics at the existing seam). The plugin dogfoods itself: its documentation lives in docs/plugins/docs-plugin.md and renders through its own pipeline.

Evidence

  • Before: no /docs route; createPluginBaseConfig dropped options.rspack.plugins (hardcoded after the spread).
  • After:
    • every-plugin build compiles content inside the rspack train ([VELITE] build finished in the log; clean-checkout verified by deleting .velite first) — 132 docs, unique slugs, glossary included
    • Live stack: POST /api/rpc/docs/getBySlug → glossary JSON through the host's plugin RPC; plugin's own OpenAPI surface serves REST GET /api/docs/{slug} (+ 404s unknown slugs)
    • Browser spec (tests/regression/browser/specs/docs-plugin.spec.ts): 3/3 green with trace artifacts — index lists ≥10 docs, click-through renders reader with highlighted code, unknown slug renders not-found
    • plugin-base-config.test.ts: 3/3 — extras appended after defaults, order preserved, defaults unchanged without overrides
    • Typecheck train 14/14 · lint 0 errors · full test suite green (1291 + 194 + 140 across workspaces)

Merge Danger

Door: two-way

Revert the commit and the app returns to the core-only tree; nothing persisted (no migrations, no config state beyond one bos.app.ts entry).

Blast Radius: platform-wide

The composition changes every deploy: bos.app.ts registers a new plugin (host loads it in the plugin DAG), every-plugin's build composition gains the extraPlugins merge point (no behavior change when unused — covered by test), and the core sidebar map adds the book icon (additive). Velite pins zod v3 internally for its own config — isolated to the build step, no runtime sharing.

…blic UI (#444)

Implements the docs-plugin epic: the repository's own markdown (docs/** +
GLOSSARY.md) compiled at build time by velite through a rspack
beforeCompile hook, served read-only via oRPC and rendered in a gate-free
public UI.

- every-plugin: build.config.ts gains extraPlugins — rspack plugin
  instances appended after the composed defaults (#445)
- plugins/docs: velite pipeline, listPublished/getBySlug routes, no DB,
  no secrets (#446)
- docs ui: /docs index + splat reader under the public mount, shared
  MarkdownRenderer (react-markdown + shiki JS engine), sidebar nav entry
  via the new book icon (#447)
- browser regression spec with trace artifacts; changesets for
  every-plugin and @everything-dev/docs-plugin (#448)
- the plugin documents itself in docs/plugins/docs-plugin.md through its
  own pipeline (#449)

Closes #444
@railway-app
railway-app Bot temporarily deployed to heartfelt-ambition / everything-dev-pr-450 October 16, 2026 21:57 Destroyed
@railway-app

railway-app Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

🚅 Deployed to the everything-dev-pr-450 environment in heartfelt-ambition

Service Status Web Updated
upload.everything.dev ✅ Success (View Logs) Oct 18, 2026 at 10:44 pm UTC
8 services not affected by this PR
  • dev-app
  • api-db-6AR0
  • auth-db
  • api-db
  • auth-db-ISTt
  • projects-db
  • projects
  • app

Takes the docs plugin's two routes from plain lists to the prototype's
catalog language, still fully shadcn:

- index: search input + tag filter pills + "N / M docs" count, docs as
  cards (order number, title, description, tag badges) grouped under
  uppercase tracked micro-headers, filtering via listPublished({ q, tag })
- reader: article in a Card with tag badges and prev/next footer nav
  following the API's order/slug ordering
- MarkdownRenderer: bordered code panels with a working copy button;
  blockquote as note-block styling
- shadcn primitives (card, badge, input, button) added to the plugin ui;
  E2E spec extended to 6 tests (search, tag filter, prev/next, copy)

Closes #444
@railway-app
railway-app Bot temporarily deployed to heartfelt-ambition / everything-dev-pr-450 October 16, 2026 22:17 Destroyed
…stamp-stamped stack lifecycle

The start:ssr leg failed for two independent fixture gaps, both fixed
generically:

- scripts/regression/container-build.ts staged auth's folder-form UI only;
  ui-ful plugins (docs, ai) resolved with no production URL and the
  composer dropped their routes. The fixture now stages every local
  plugin's ui dist with the deploy train's shape (bundle key <key>-ui,
  production/ssr URL from the variant, pin, built container name).
- .dockerignore excluded the repository docs tree, so the docs plugin's
  velite compile inside the dist-builder only produced GLOSSARY.md
  (38 docs in the repo → 1 seeded record): the tree stays in the build
  context (the prod stage strips sources; runtime images never carry it).
- ssr-compose.spec asserted exactly 2 manifests (core + auth) — with
  plugin UIs composing it embeds more; pinned to include the docs-ui
  manifest instead.
- start-container.mjs is replaced by regression-stack.mjs:
  content-stamped (HEAD + diff + porcelain + lockfile + Dockerfile/
  compose + regression environment) detached docker run, reuse on
  same-stamp healthy, reap otherwise, cleanup-before-probe in the
  test:regression:browser:start:* scripts, and a global teardown leaving
  the stack down after every graceful run. No new stale-container class
  from a SIGKILLed webServer child.
@railway-app
railway-app Bot temporarily deployed to heartfelt-ambition / everything-dev-pr-450 October 18, 2026 22:29 Destroyed
Playwright treats a webServer command that exits after booting as
boot-failed regardless of URL health. Chain a watch step after ensure:
tail the detached container, exit non-zero if it dies mid-suite, remove
it on the teardown signals. A graceful end still leaves the stack down
(global teardown removes the same-stamp container anyway); a SIGKILLed
caller leaves only the healthy detached container, reused or reaped by
the next run.

This branch was successfully deployed

1 active deployment
heartfelt-ambition / everything-dev-pr-450 — ca861c8d Deployed Oct 18, 2026 by railway-app[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Docs plugin (v1): Velite content pipeline — repo-authored, read-only

1 participant