Skip to content

Storybook component showcase with Tailwind, interaction tests and Coolify deployment #8

Description

@hendrikebbers

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

  • pnpm storybook serves a catalogue listing MarkdownEditor and MarkdownView
  • Components render with brand tokens and resolved Tailwind utilities; task lists show a checkbox and no prose bullet
  • The toolbar prop is adjustable at runtime and the editor story shows the serialized Markdown next to the editor
  • A MarkdownView story exposes latency and a "next save fails" switch, and demonstrates optimistic flip, disabled-while-pending and rollback on failure
  • play functions assert the toolbar allowlist, the task-list creation gate, accessible button names, and the checkbox lifecycle after real clicks
  • pnpm test still passes and no existing test file was modified
  • pnpm build-storybook produces storybook-static/
  • pnpm build produces a dist/ free of story files; dependencies and peerDependencies are unchanged; nothing under src/ imports @storybook/*
  • The container image builds and serves the showcase at the root path
  • Coolify redeploys on push to main
  • Unauthenticated visitors are redirected to Authentik; only members of the bound group reach the showcase; iframe.html and assets are covered by the same session

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions