;
+
+export const WithError: Story = {
+ args: {
+ colorScheme: errorBoundaryDefaultColorScheme,
+ children: ,
+ },
+};
+
+export const NoError: Story = {
+ args: {
+ colorScheme: errorBoundaryDefaultColorScheme,
+ children: (
+
+ This content renders normally when no error occurs.
+
+ ),
+ },
+};
diff --git a/.storybook/stories/ui/utilities/HelpTooltip.stories.tsx b/.storybook/stories/ui/utilities/HelpTooltip.stories.tsx
new file mode 100644
index 000000000..25aee5458
--- /dev/null
+++ b/.storybook/stories/ui/utilities/HelpTooltip.stories.tsx
@@ -0,0 +1,36 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import { HelpTooltip } from '../../../../packages/ui/src/index';
+
+const meta = {
+ title: 'UI/Utilities/HelpTooltip',
+ component: HelpTooltip,
+ tags: ['autodocs'],
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ term: 'Cpk',
+ content:
+ 'Process Capability Index (Cpk) measures how well a process meets specification limits, accounting for both spread and centering.',
+ },
+};
+
+export const WithLearnMore: Story = {
+ args: {
+ term: 'Control Limits',
+ content:
+ 'Control limits (UCL/LCL) are calculated from the data as mean plus/minus 3 sigma. They represent the natural voice of the process.',
+ learnMoreUrl: '#',
+ },
+};
+
+export const LongContent: Story = {
+ args: {
+ term: 'ANOVA',
+ content:
+ 'Analysis of Variance (ANOVA) tests whether the means of different groups are statistically different. A significant result (p < 0.05) indicates that at least one group mean differs. The eta-squared value shows what percentage of total variation is explained by the factor.',
+ },
+};
diff --git a/.storybook/stories/ui/utilities/UpgradePrompt.stories.tsx b/.storybook/stories/ui/utilities/UpgradePrompt.stories.tsx
new file mode 100644
index 000000000..bba7afcd6
--- /dev/null
+++ b/.storybook/stories/ui/utilities/UpgradePrompt.stories.tsx
@@ -0,0 +1,29 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import { UpgradePrompt } from '../../../../packages/ui/src/index';
+
+const meta = {
+ title: 'UI/Utilities/UpgradePrompt',
+ component: UpgradePrompt,
+ tags: ['autodocs'],
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ feature: 'Performance Mode',
+ description:
+ 'Analyze up to 1,500 measurement channels simultaneously with the Azure Standard plan.',
+ },
+};
+
+export const ChannelLimit: Story = {
+ args: {
+ feature: 'More Channels',
+ description:
+ 'The free tier supports up to 5 channels. Upgrade to Azure for up to 1,500 channels.',
+ currentCount: 5,
+ maxCount: 5,
+ },
+};
diff --git a/CLAUDE.md b/CLAUDE.md
index 2f54d0036..c803227ad 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -16,6 +16,14 @@ pnpm --filter @variscout/azure-app test # Azure app tests only
claude --chrome # Enable Chrome browser for E2E testing
+pnpm storybook # Component catalog (localhost:6006)
+pnpm build-storybook # Build static Storybook
+
+pnpm docs:dev # Starlight doc site (localhost:4321)
+pnpm docs:build # Build static doc site
+pnpm docs:c4 # Export LikeC4 → Mermaid
+pnpm docs:c4:serve # Interactive C4 browser
+
npx ruflo@latest security scan --depth full # OWASP security scan
npx ruflo@latest security cve --check # CVE check
@@ -43,6 +51,7 @@ npx ruflo@latest security cve --check # CVE check
| docs/08-products/ | Azure, PWA, website specs, feature-parity matrix |
| docs/09-tutorials/ | Planned step-by-step guides |
| docs/superpowers/specs/ | Design specs from brainstorming sessions (see index.md) |
+| docs/architecture/ | LikeC4 model (C4 L1-L3 source of truth) |
| docs/archive/ | HISTORICAL ONLY — removed features, do not reference for current work |
## Task → Documentation
@@ -70,6 +79,8 @@ npx ruflo@latest security cve --check # CVE check
| Teams integration | adr-016, docs/08-products/azure/authentication.md |
| Platform comparison | docs/08-products/feature-parity.md |
| Knowledge model / Glossary | docs/05-technical/architecture/knowledge-model.md, packages/core/src/glossary/ |
+| C4 architecture model | docs/architecture/likec4/ |
+| Documentation site | apps/docs/ (Astro + Starlight) |
## Repository Structure
@@ -87,7 +98,8 @@ variscout-lite/
├── apps/
│ ├── pwa/ # PWA website (React + Vite)
│ ├── azure/ # Azure Team App (EasyAuth + OneDrive sync)
-│ └── website/ # Marketing website (Astro + React Islands)
+│ ├── website/ # Marketing website (Astro + React Islands)
+│ └── docs/ # Documentation site (Astro + Starlight)
├── infra/ # ARM template + Azure Functions
└── docs/ # Documentation (see table above)
```
diff --git a/apps/docs/.astro/collections/docs.schema.json b/apps/docs/.astro/collections/docs.schema.json
new file mode 100644
index 000000000..a663eb8f9
--- /dev/null
+++ b/apps/docs/.astro/collections/docs.schema.json
@@ -0,0 +1,595 @@
+{
+ "$ref": "#/definitions/docs",
+ "definitions": {
+ "docs": {
+ "type": "object",
+ "properties": {
+ "title": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "editUrl": {
+ "anyOf": [
+ {
+ "type": "string",
+ "format": "uri"
+ },
+ {
+ "type": "boolean"
+ }
+ ],
+ "default": true
+ },
+ "head": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "tag": {
+ "type": "string",
+ "enum": ["title", "base", "link", "style", "meta", "script", "noscript", "template"]
+ },
+ "attrs": {
+ "type": "object",
+ "additionalProperties": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "boolean"
+ },
+ {
+ "not": {}
+ }
+ ]
+ }
+ },
+ "content": {
+ "type": "string"
+ }
+ },
+ "required": ["tag"],
+ "additionalProperties": false
+ },
+ "default": []
+ },
+ "tableOfContents": {
+ "anyOf": [
+ {
+ "type": "object",
+ "properties": {
+ "minHeadingLevel": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 6,
+ "default": 2
+ },
+ "maxHeadingLevel": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 6,
+ "default": 3
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "boolean"
+ }
+ ],
+ "default": {
+ "minHeadingLevel": 2,
+ "maxHeadingLevel": 3
+ }
+ },
+ "template": {
+ "type": "string",
+ "enum": ["doc", "splash"],
+ "default": "doc"
+ },
+ "hero": {
+ "type": "object",
+ "properties": {
+ "title": {
+ "type": "string"
+ },
+ "tagline": {
+ "type": "string"
+ },
+ "image": {
+ "anyOf": [
+ {
+ "type": "object",
+ "properties": {
+ "alt": {
+ "type": "string",
+ "default": ""
+ },
+ "file": {
+ "type": "string"
+ }
+ },
+ "required": ["file"],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "alt": {
+ "type": "string",
+ "default": ""
+ },
+ "dark": {
+ "type": "string"
+ },
+ "light": {
+ "type": "string"
+ }
+ },
+ "required": ["dark", "light"],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "html": {
+ "type": "string"
+ }
+ },
+ "required": ["html"],
+ "additionalProperties": false
+ }
+ ]
+ },
+ "actions": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "text": {
+ "type": "string"
+ },
+ "link": {
+ "type": "string"
+ },
+ "variant": {
+ "type": "string",
+ "enum": ["primary", "secondary", "minimal"],
+ "default": "primary"
+ },
+ "icon": {
+ "anyOf": [
+ {
+ "type": "string",
+ "enum": [
+ "up-caret",
+ "down-caret",
+ "right-caret",
+ "left-caret",
+ "up-arrow",
+ "down-arrow",
+ "right-arrow",
+ "left-arrow",
+ "bars",
+ "translate",
+ "pencil",
+ "pen",
+ "document",
+ "add-document",
+ "setting",
+ "external",
+ "download",
+ "cloud-download",
+ "moon",
+ "sun",
+ "laptop",
+ "open-book",
+ "information",
+ "magnifier",
+ "forward-slash",
+ "close",
+ "error",
+ "warning",
+ "approve-check-circle",
+ "approve-check",
+ "rocket",
+ "star",
+ "puzzle",
+ "list-format",
+ "random",
+ "comment",
+ "comment-alt",
+ "heart",
+ "github",
+ "gitlab",
+ "bitbucket",
+ "codePen",
+ "farcaster",
+ "discord",
+ "gitter",
+ "twitter",
+ "x.com",
+ "mastodon",
+ "codeberg",
+ "youtube",
+ "threads",
+ "linkedin",
+ "twitch",
+ "azureDevOps",
+ "microsoftTeams",
+ "instagram",
+ "stackOverflow",
+ "telegram",
+ "rss",
+ "facebook",
+ "email",
+ "phone",
+ "reddit",
+ "patreon",
+ "signal",
+ "slack",
+ "matrix",
+ "hackerOne",
+ "openCollective",
+ "blueSky",
+ "discourse",
+ "zulip",
+ "pinterest",
+ "tiktok",
+ "astro",
+ "alpine",
+ "pnpm",
+ "biome",
+ "bun",
+ "mdx",
+ "apple",
+ "linux",
+ "homebrew",
+ "nix",
+ "starlight",
+ "pkl",
+ "node",
+ "cloudflare",
+ "vercel",
+ "netlify",
+ "deno",
+ "jsr",
+ "nostr",
+ "backstage",
+ "confluence",
+ "jira",
+ "storybook",
+ "vscode",
+ "jetbrains",
+ "zed",
+ "vim",
+ "figma",
+ "sketch",
+ "npm",
+ "sourcehut",
+ "substack",
+ "seti:folder",
+ "seti:bsl",
+ "seti:mdo",
+ "seti:salesforce",
+ "seti:asm",
+ "seti:bicep",
+ "seti:bazel",
+ "seti:c",
+ "seti:c-sharp",
+ "seti:html",
+ "seti:cpp",
+ "seti:clojure",
+ "seti:coldfusion",
+ "seti:config",
+ "seti:crystal",
+ "seti:crystal_embedded",
+ "seti:json",
+ "seti:css",
+ "seti:csv",
+ "seti:xls",
+ "seti:cu",
+ "seti:cake",
+ "seti:cake_php",
+ "seti:d",
+ "seti:word",
+ "seti:elixir",
+ "seti:elixir_script",
+ "seti:hex",
+ "seti:elm",
+ "seti:favicon",
+ "seti:f-sharp",
+ "seti:git",
+ "seti:go",
+ "seti:godot",
+ "seti:gradle",
+ "seti:grails",
+ "seti:graphql",
+ "seti:hacklang",
+ "seti:haml",
+ "seti:mustache",
+ "seti:haskell",
+ "seti:haxe",
+ "seti:jade",
+ "seti:java",
+ "seti:javascript",
+ "seti:jinja",
+ "seti:julia",
+ "seti:karma",
+ "seti:kotlin",
+ "seti:dart",
+ "seti:liquid",
+ "seti:livescript",
+ "seti:lua",
+ "seti:markdown",
+ "seti:argdown",
+ "seti:info",
+ "seti:clock",
+ "seti:maven",
+ "seti:nim",
+ "seti:github",
+ "seti:notebook",
+ "seti:nunjucks",
+ "seti:npm",
+ "seti:ocaml",
+ "seti:odata",
+ "seti:perl",
+ "seti:php",
+ "seti:pipeline",
+ "seti:pddl",
+ "seti:plan",
+ "seti:happenings",
+ "seti:powershell",
+ "seti:prisma",
+ "seti:pug",
+ "seti:puppet",
+ "seti:purescript",
+ "seti:python",
+ "seti:react",
+ "seti:rescript",
+ "seti:R",
+ "seti:ruby",
+ "seti:rust",
+ "seti:sass",
+ "seti:spring",
+ "seti:slim",
+ "seti:smarty",
+ "seti:sbt",
+ "seti:scala",
+ "seti:ethereum",
+ "seti:stylus",
+ "seti:svelte",
+ "seti:swift",
+ "seti:db",
+ "seti:terraform",
+ "seti:tex",
+ "seti:default",
+ "seti:twig",
+ "seti:typescript",
+ "seti:tsconfig",
+ "seti:vala",
+ "seti:vite",
+ "seti:vue",
+ "seti:wasm",
+ "seti:wat",
+ "seti:xml",
+ "seti:yml",
+ "seti:prolog",
+ "seti:zig",
+ "seti:zip",
+ "seti:wgt",
+ "seti:illustrator",
+ "seti:photoshop",
+ "seti:pdf",
+ "seti:font",
+ "seti:image",
+ "seti:svg",
+ "seti:sublime",
+ "seti:code-search",
+ "seti:shell",
+ "seti:video",
+ "seti:audio",
+ "seti:windows",
+ "seti:jenkins",
+ "seti:babel",
+ "seti:bower",
+ "seti:docker",
+ "seti:code-climate",
+ "seti:eslint",
+ "seti:firebase",
+ "seti:firefox",
+ "seti:gitlab",
+ "seti:grunt",
+ "seti:gulp",
+ "seti:ionic",
+ "seti:platformio",
+ "seti:rollup",
+ "seti:stylelint",
+ "seti:yarn",
+ "seti:webpack",
+ "seti:lock",
+ "seti:license",
+ "seti:makefile",
+ "seti:heroku",
+ "seti:todo",
+ "seti:ignored"
+ ]
+ },
+ {
+ "type": "string",
+ "pattern": "^\\