The library exports 58 symbols across roughly 30 components and is consumed by two applications, but there is no way to look at a component without building an app around it.
The Markdown components make the gap concrete. Specs 001–003 are implemented and their vitest suites pass, yet nobody has seen a task list render inside a prose container, and the interactive-checkbox behaviour from spec 003 is verified by calling onReadOnlyChecked directly under jsdom rather than by clicking anything. Spec 001 also recorded an unverified precondition — that consuming apps scan the library sources in their Tailwind content configuration — which nothing in this repository currently exercises, because Tailwind is installed nowhere here.
Proposal
Add a Storybook-based showcase: a browsable, interactive catalogue with Tailwind wired up so components look the way they will in a consuming app, plus a self-hosted deployment behind Authentik SSO.
- Storybook 10.5.8 with
@storybook/react-vite, @storybook/addon-docs and @storybook/addon-a11y. Vite 7.3.2 and @vitejs/plugin-react are already present as vitest dependencies. Peer ranges verified against the registry: Vite ^5 || ^6 || ^7 || ^8, React ^16.8 || ^17 || ^18 || ^19.
- Tailwind v4 (
tailwindcss, @tailwindcss/vite, @tailwindcss/typography) loaded from a single Storybook preview stylesheet that imports src/styles/brand.css and declares @source "../src". @tailwindcss/typography is required because MarkdownView hardcodes prose prose-sm.
- Stories live in a top-level
stories/ directory, not next to the components. package.json declares files: ["dist", "src"] and consumers compile the raw .tsx themselves, so a colocated story would ship in the tarball and break their tsc on unresolvable @storybook/* imports.
- A save mock as a function, not a server. The components speak callbacks, not HTTP.
MarkdownView.onChange returns void | Promise<void>, so latency, success and failure are exposed as Storybook args. MSW is deliberately not used — it would test the story's plumbing rather than the component.
play functions covering the interaction scenarios from specs 002 and 003 in a real browser, using storybook/test (the subpath export; @storybook/test is not published for 10.x). These are additive; existing vitest suites are not touched.
- Deployment to Coolify via a multi-stage
Dockerfile (node:24-alpine build → nginx serve), with a .dockerignore for node_modules, dist and storybook-static. A Dockerfile rather than Coolify's static build pack, so the build command and output directory stay versioned and reproducible locally.
- Authentik forward auth in front of it: a Proxy Provider in Forward auth (single application) mode on the embedded outpost, attached through custom Traefik labels on the Coolify application. Group-based access instead of a shared password, and no change to the static build.
Scope
Infrastructure plus stories for MarkdownEditor and MarkdownView, which establish the pattern. The remaining ~28 components follow incrementally and do not need their own issue.
Out of scope
- Stories for all components in this issue
- Changes to existing vitest tests
- MSW or any HTTP mocking
- Visual regression testing (Chromatic or equivalent)
- Any change to
dependencies or peerDependencies — everything lands in devDependencies
- Adding
build-storybook to CI
Acceptance criteria
Prerequisites
Two infrastructure facts are needed before the deployment part can be implemented:
- Does the Coolify instance proxy with Traefik or Caddy? Caddy needs a
forward_auth directive instead of Traefik labels.
- Can Authentik reach the showcase container over a shared Docker network, or does the forward-auth address have to be Authentik's public URL?
Also open: the hostname for the showcase and who configures the DNS entry.
Reference
Full design and 28 behavioral scenarios: specs/004-component-showcase/ — design.md, behaviors.md.
Tooling only; no published version bump.
The library exports 58 symbols across roughly 30 components and is consumed by two applications, but there is no way to look at a component without building an app around it.
The Markdown components make the gap concrete. Specs 001–003 are implemented and their vitest suites pass, yet nobody has seen a task list render inside a
prosecontainer, and the interactive-checkbox behaviour from spec 003 is verified by callingonReadOnlyCheckeddirectly under jsdom rather than by clicking anything. Spec 001 also recorded an unverified precondition — that consuming apps scan the library sources in their Tailwind content configuration — which nothing in this repository currently exercises, because Tailwind is installed nowhere here.Proposal
Add a Storybook-based showcase: a browsable, interactive catalogue with Tailwind wired up so components look the way they will in a consuming app, plus a self-hosted deployment behind Authentik SSO.
@storybook/react-vite,@storybook/addon-docsand@storybook/addon-a11y. Vite 7.3.2 and@vitejs/plugin-reactare already present as vitest dependencies. Peer ranges verified against the registry: Vite^5 || ^6 || ^7 || ^8, React^16.8 || ^17 || ^18 || ^19.tailwindcss,@tailwindcss/vite,@tailwindcss/typography) loaded from a single Storybook preview stylesheet that importssrc/styles/brand.cssand declares@source "../src".@tailwindcss/typographyis required becauseMarkdownViewhardcodesprose prose-sm.stories/directory, not next to the components.package.jsondeclaresfiles: ["dist", "src"]and consumers compile the raw.tsxthemselves, so a colocated story would ship in the tarball and break theirtscon unresolvable@storybook/*imports.MarkdownView.onChangereturnsvoid | Promise<void>, so latency, success and failure are exposed as Storybook args. MSW is deliberately not used — it would test the story's plumbing rather than the component.playfunctions covering the interaction scenarios from specs 002 and 003 in a real browser, usingstorybook/test(the subpath export;@storybook/testis not published for 10.x). These are additive; existing vitest suites are not touched.Dockerfile(node:24-alpinebuild → nginx serve), with a.dockerignorefornode_modules,distandstorybook-static. A Dockerfile rather than Coolify's static build pack, so the build command and output directory stay versioned and reproducible locally.Scope
Infrastructure plus stories for
MarkdownEditorandMarkdownView, which establish the pattern. The remaining ~28 components follow incrementally and do not need their own issue.Out of scope
dependenciesorpeerDependencies— everything lands indevDependenciesbuild-storybookto CIAcceptance criteria
pnpm storybookserves a catalogue listingMarkdownEditorandMarkdownViewprosebullettoolbarprop is adjustable at runtime and the editor story shows the serialized Markdown next to the editorMarkdownViewstory exposes latency and a "next save fails" switch, and demonstrates optimistic flip, disabled-while-pending and rollback on failureplayfunctions assert the toolbar allowlist, the task-list creation gate, accessible button names, and the checkbox lifecycle after real clickspnpm teststill passes and no existing test file was modifiedpnpm build-storybookproducesstorybook-static/pnpm buildproduces adist/free of story files;dependenciesandpeerDependenciesare unchanged; nothing undersrc/imports@storybook/*mainiframe.htmland assets are covered by the same sessionPrerequisites
Two infrastructure facts are needed before the deployment part can be implemented:
forward_authdirective instead of Traefik labels.Also open: the hostname for the showcase and who configures the DNS entry.
Reference
Full design and 28 behavioral scenarios:
specs/004-component-showcase/—design.md,behaviors.md.Tooling only; no published version bump.