Skip to content

FRD: Add Stories for Undocumented Internal Components

FieldValue
IDFRD-047
OwnerDavid Holmes
StatusShipped
Last Updated2026-05-26
Target Releasev2.1.0
TypeInfra
ComplexityM

Document Summary

Eight UI components in src/components/ui/ lack Storybook stories and documentation. This FRD defines the work to add stories for each component using the createComponentDocs pattern, mark internal-only helpers with @internal JSDoc, and ensure all components are visually covered in Storybook for regression testing and discoverability.


Introduction

Overview

The design system has eight components without Storybook stories: scorecard.tsx, gauge-ring.tsx, manifest-viewer.tsx, filter-pill-bar.tsx, overlay-caret.tsx, search-result-row.tsx, slide-out-panel-manager.tsx, and pod-terminal-live-session.tsx. Without stories, these components are invisible to consumers browsing Storybook, untested by visual regression, and undocumented for usage patterns.

Goals

  • Add a Storybook story file for each of the eight components.
  • Use the createComponentDocs utility for consistent documentation structure.
  • Mark internal-only components with @internal JSDoc so consumers know the stability contract.
  • Ensure every story renders correctly in pnpm build-storybook.

Non-Goals

  • Redesigning or refactoring any of these components.
  • Deciding public vs. internal export status (covered by FRD-048, barrel export audit).
  • Adding interaction tests beyond visual snapshots.

Scope

In Scope

ItemDescription
scorecard.stories.tsxStory for the scorecard metric display component (74 lines).
gauge-ring.stories.tsxStory for the circular gauge visualization (150 lines).
manifest-viewer.stories.tsxStory for the YAML/JSON manifest viewer (9 lines — may be a re-export or stub).
filter-pill-bar.stories.tsxStory for the filter pill bar component (115 lines).
overlay-caret.stories.tsxStory for the overlay positioning caret (108 lines).
search-result-row.stories.tsxStory for the search result list item (236 lines).
slide-out-panel-manager.stories.tsxStory for the slide-out panel container (234 lines).
pod-terminal-live-session.stories.tsxStory for the live terminal session component (182 lines).
@internal JSDocAdd @internal tag to components confirmed as internal helpers.

Out of Scope

ItemReason
Barrel export decisionsCovered by FRD-048.
Component refactoringStories document current behavior, not desired behavior.
Interaction or accessibility testsCan be added as follow-up; this FRD covers visual stories only.

Users and Pain Points

UserPain Point
Component consumerCannot discover these components in Storybook; must read source code to learn about them.
Visual regression CIThese components are not covered by visual snapshots, so regressions go undetected.
New team memberNo documentation for usage patterns, props, or expected behavior of these components.
Design reviewerCannot review visual appearance of these components in Storybook without running the app.

Definitions

TermDefinition
createComponentDocsA utility function used across the design system to generate consistent Storybook documentation pages with prop tables, usage examples, and design notes.
@internal JSDocA JSDoc tag indicating that a component is not part of the public API and may change without notice.
Visual regressionAutomated screenshot comparison that detects unintended visual changes between builds.

Current State

The eight components exist in src/components/ui/ and are used internally by other components or application surfaces. None have corresponding .stories.tsx files. Component sizes range from 9 lines (manifest-viewer.tsx, likely a re-export) to 236 lines (search-result-row.tsx). None have @internal JSDoc tags despite several being internal implementation details.


Proposed Solution

For each of the eight components:

  1. Create a story file adjacent to the component (e.g., scorecard.stories.tsx next to scorecard.tsx).
  2. Use createComponentDocs to generate the docs page with:
    • Component description.
    • Prop table (auto-generated from TypeScript types).
    • A default story showing typical usage.
    • At least one variant story showing a key alternative state (e.g., empty state, loading state, error state).
  3. Story title follows the Storybook sidebar governance (ADR-016). Place under the existing Components/UI/ path.
  4. For components confirmed as internal helpers (those not in the barrel export), add /** @internal */ JSDoc above the component export.

Story placement per ADR-016

All stories go under Components/UI/[ComponentName] since these are UI-layer components. No new Storybook root section is created.


Requirements

IDPriorityRequirement
STORY-01P0Each of the 8 components has a .stories.tsx file.
STORY-02P0Each story uses createComponentDocs for the docs page.
STORY-03P0Each story includes a default story and at least one variant.
STORY-04P0All stories render without errors in pnpm build-storybook.
STORY-05P1Internal-only components have @internal JSDoc.
STORY-06P1Story titles follow ADR-016 sidebar governance.

Functional Requirements

  1. Scorecard: Default story shows a scorecard with label, value, and trend indicator. Variant shows scorecard with no trend (neutral state).
  2. Gauge Ring: Default story shows a gauge at 75% fill. Variants for 0%, 50%, and 100%. Variant for custom color.
  3. Manifest Viewer: Default story shows a sample YAML manifest. Variant shows JSON format.
  4. Filter Pill Bar: Default story shows 3-4 active filter pills. Variant shows empty state (no filters). Variant shows overflow (many pills).
  5. Overlay Caret: Default story shows the caret positioned above a target. Variants for each position (top, bottom, left, right).
  6. Search Result Row: Default story shows a result with title, snippet, and metadata. Variant shows highlighted search terms. Variant shows result without snippet.
  7. Slide Out Panel Manager: Default story shows the panel in open state with sample content. Variant shows closed/collapsed state. Variant shows panel with header actions.
  8. Pod Terminal Live Session: Default story shows a terminal with sample output lines. Variant shows connection-pending state. Variant shows disconnected state.

Non-Functional Requirements

CategoryRequirement
ConsistencyAll stories use the same documentation pattern (createComponentDocs) as existing component stories.
Build timeStories should not significantly increase Storybook build time (estimated less than 5 seconds additional).
Snapshot stabilityStories should produce deterministic screenshots (no animations in default state, mocked data).

API/Interface Requirements

No API changes. Stories document the existing component APIs.


Accessibility Requirements

  • Each story should render the component in an accessible state (proper ARIA attributes, keyboard focus visible).
  • The createComponentDocs output includes an accessibility section noting any ARIA requirements.
  • Stories for interactive components (filter-pill-bar, slide-out-panel-manager) should demonstrate keyboard interaction in the docs page.

Content and Documentation Requirements

  • Each createComponentDocs call includes:
    • A one-sentence component description.
    • A “When to use” note.
    • A “When not to use” note (if applicable).
    • Props table (auto-generated).
  • For @internal components, the description includes a note that the component is internal and may change.

Dependencies

DependencyTypeNotes
createComponentDocsInternalExisting utility for story documentation.
ADR-016GovernanceSidebar placement rules.
ADR-017GovernanceDocs truthfulness rules.
The 8 component source filesInternalsrc/components/ui/.

Risks and Tradeoffs

RiskLikelihoodImpactMitigation
manifest-viewer.tsx is only 9 lines and may not have meaningful props to document.HighLowIf it is a simple re-export, the story just re-exports the upstream story or shows the composition.
pod-terminal-live-session.tsx depends on heavy runtime deps (xterm).MediumMediumMock the terminal output in the story; do not connect to a real terminal. The lazy-loading FRD (FRD-049) addresses the bundle cost.
Story mocking may diverge from real component behavior.LowLowUse the simplest mocks possible. Document any mocking in story source comments.

Open Questions

  1. Should manifest-viewer.tsx get its own story or be folded into a parent component’s story? Depends on whether it has standalone props.
  2. Should stories for pod-terminal-live-session.tsx be gated behind a lazy-load boundary (coordinated with FRD-049)?
  3. Should @internal components be placed under a separate Storybook path like Components/Internal/? ADR-016 does not currently define this. Leaning toward keeping under Components/UI/ with an [Internal] suffix in the story title.

Acceptance Criteria

  • 8 new .stories.tsx files exist in src/components/ui/.
  • Each story uses createComponentDocs.
  • Each story has at least a default and one variant.
  • All stories render without errors in pnpm build-storybook.
  • Internal-only components have @internal JSDoc on their exports.
  • Story titles follow ADR-016 sidebar governance (no new root sections).
  • pnpm typecheck passes.
  • pnpm vitest run --project unit passes.

LLM Handoff Instructions

When implementing this FRD:

  1. For each component, read the source file to understand props, states, and usage context.
  2. Create the story file adjacent to the component. Follow the pattern of an existing story in src/components/ui/ (e.g., look for a well-documented component with createComponentDocs).
  3. Set the story title to Components/UI/[ComponentName]. If the component is internal, append [Internal] to the title.
  4. Import createComponentDocs from the shared story utility. Pass the component, description, and any configuration.
  5. Create a Default story with representative props. Create at least one additional variant.
  6. For pod-terminal-live-session.stories.tsx, mock terminal output rather than connecting to a real session. Use static sample lines.
  7. For manifest-viewer.tsx, check if it re-exports another component. If so, the story can demonstrate the composition.
  8. Add /** @internal */ JSDoc to component exports that are not in src/index.ts barrel exports.
  9. Run pnpm build-storybook to confirm all stories render.
  10. Run pnpm typecheck and pnpm vitest run --project unit.

Decision Log

DateDecisionRationale
2026-05-26Use createComponentDocs for all stories.Consistent with existing design system documentation pattern.
2026-05-26Place all stories under Components/UI/.Follows ADR-016; no new root sections.
2026-05-26Mark internal components with @internal JSDoc.Communicates stability contract without removing or hiding components.

Document History

VersionDateAuthorChanges
0.12026-05-26David HolmesInitial draft.