- Status: decided deployment contract before the Storybook build exists; commands and routes below describe the future realized delivery.
- Dependencies: 30-first-delivery defines the component and browser contract; 10-topology-options defines renderer/CSS separation; 20-fleet-evidence records source provenance.
Build runtime
| Layer | Required or accepted version | Basis and boundary |
|---|---|---|
| Node | v22.23.1 | Existing owner-probed runtime; retained for building and the static server |
| npm | 10.9.8 | Existing owner-probed package manager; installs and lockfile confined to stbk |
| Storybook | 10.6.0 | Chosen version, not a dependency already present in the fleet projects |
| Framework | @storybook/svelte-vite 10.6.0 | One native Svelte renderer per instance |
| Svelte | 5.57.0 | Common resolved version in the three selected Svelte projects |
| Vite | Major 8 accepted by the framework peer range | The exact installed patch will be recorded in stbk’s lockfile; source locks contain both 8.2.2 and 8.3.0 |
| Svelte Vite plugin | @sveltejs/vite-plugin-svelte 7.3.0 | Source-resolved integration version, within the framework’s accepted plugin range |
| Tailwind | tailwindcss and @tailwindcss/vite 4.3.3 | CSS-first pipeline; external source discovery must be explicit |
| daisyUI | 5.7.38 | Fleet preview only, with four replicated custom themes |
| Bits UI | bits-ui 2.19.0 | Separate bits preview; not a replacement for the source ink stylesheet |
| Flow | @xyflow/svelte 1.6.6 | Real StudioNode fixture and required Flow stylesheet |
| Icons | @lucide/svelte 1.37.0 | Dependency of the three selected bits demonstrations |
| Chat Markdown | Not installed | Not installed. Formatted display cases use recorded, pre-sanitized block fixtures; local edit results use escaped Svelte text rendering. No runtime Markdown conversion or sanitizer equivalence is claimed. |
- Compatibility evidence:
- The published framework package metadata includes Svelte 5 and Vite 8 in its peer ranges.
- Peer acceptance is not a performed install/build proof. The owner will verify the resolved dependency graph and browser execution under the retained runtime.
- The two Storybooks will use standalone Svelte/Vite configuration, not import SvelteKit application bootstraps or sibling package-install workflows.
- Runtime fence:
- No Node or Bun replacement is permitted; installed runtime binaries and global configuration will remain untouched.
- A newly discovered higher runtime requirement will be a blocker, not an upgrade mandate or permission to force an incompatible installation.
- Package and lockfile changes will belong only to stbk. No sibling install, migration, formatter, or build command will be run as a side effect of component reuse.
Serving model
- Artifacts:
- The root
fleetinstance will build to the deploy root. - The separately built
bitsinstance will occupy abitssubdirectory of that same root. Build staging/assembly must prevent the root build from deleting the referenced output. - One dependency-free Node static server will serve the entire tree. Composition will not require a second server process or a second backend port.
- The root
- Build and public routes:
- Storybook 10.6.0’s Vite builder defaults to
base: './', and its manager emits relative asset and index URLs. Build both instances normally into separate staging outputs, then assemble the deploy tree; no requiredviteFinalbase override or custom preview URL is needed. Redirect/bitsto/bits/while preserving the query string. The standalone manager is/bits/?path=/story/<story-id>, its preview is/bits/iframe.html?id=<story-id>&viewMode=story, and the composed manager link is/?path=/story/bits_<story-id>. Missing files must not fall back to either manager HTML. - Use normal
storybook buildwith separate--config-dirand--output-dirvalues and independent staging, then assemble the output trees. Keep manager assets relative; avoid root-absolute custom media. --preview-urland--testbuilds are forbidden. The CLI build implementation skips the local preview when--preview-urlis used unless explicitly forced; getRefs removes refs in--testmode.- Version-pinned basis: Vite builder configuration, manager template, and preview URL routing.
- Storybook 10.6.0’s Vite builder defaults to
- Process:
- One systemd unit,
stbk.service, will run the Node static server as the operator account. - The server will bind only to the selected loopback endpoint and serve only the assembled Storybook output, not arbitrary sibling source paths.
- It will support the HTML, JavaScript, CSS, story indexes, and local media assets required by both instances; unknown assets will return genuine missing-resource responses rather than the root HTML document.
/bitswill resolve consistently to/bits/; direct loading and refresh of the referenced instance must work independently of root composition.
- One systemd unit,
- Endpoint selection:
- The primary and two documented substitutions were owner-probed free. Occupancy must still be checked immediately before staging the final service/proxy configuration.
- Use the first available candidate in the recorded order; a substitution must be recorded and applied to both unit/server configuration and nginx’s upstream. The server must not silently select a different endpoint.
bind-address: 127.0.0.1
operator-port-band: 51000-53000
port-order:
- 51945
- 51955
- 51965
primary-endpoint: 127.0.0.1:51945- Edge:
- Both
stbk.loca.zoneandwiki.stbk.loca.zonealready resolve to the operator host according to owner preflight; that observation does not establish application readiness. - One nginx site file will contain the two hostname server definitions.
- The application hostname will proxy to the single static server, preserving paths for the root and
/bits/output. - The wiki hostname will serve the shared wiki release root
wikis/stbk/currentdirectly; it will not proxy through the Storybook process. - One certbot run will request a certificate covering both names.
- Both
- Composition:
- The root instance’s
main.tswill reference the app origin plus/bits; the standalone referenced browser entry is/bits/. - The following is a decided configuration fragment, not a claim that the file has already been built or deployed.
- The root instance’s
refs: {
bits: {
title: 'bits',
url: 'https://stbk.loca.zone/bits',
},
}flowchart LR B["Browser"] --> A["stbk.loca.zone"] B --> W["wiki.stbk.loca.zone"] A --> N["One nginx site file"] W --> N N -->|"App proxy"| S["stbk.service: one Node static process"] S --> F["Deploy root: fleet build"] S --> R["bits subdirectory: separate build"] N -->|"Wiki static root"| Q["wikis/stbk/current"] V["stbk/q5vault source"] --> K["Shared wiki build script and lock"] K --> Q
Privilege budget
- Boundary: exactly four uses of
sudo, reserved for the owner during realization. There is no privileged implementation work delegated to story or plan authors. - Counting rule: each row is one invocation; compound operations must remain inside that bounded invocation rather than expanding into additional privileged calls.
| Use | Authorized operation | Required scope |
|---|---|---|
| 1 | Unit install | Install the staged stbk.service definition; no edits or restarts to existing fleet units |
| 2 | Nginx site install plus enable | Install/enable the single dual-host site file, validate nginx, and reload within this invocation; unrelated sites remain unchanged |
| 3 | One certbot run | Request both hostnames together, once; preserve a usable HTTP-only dual-host configuration if issuance fails |
| 4 | Unit enable/restart | Reload systemd’s unit definitions, enable and restart only stbk.service, then observe readiness |
- Before privilege:
- Build outputs and stage the unit/site definitions inside stbk.
- Confirm the selected endpoint and both hostname targets; retain the necessary rollback material without touching unrelated host configuration.
- Builds, source reads, local artifact assembly, and wiki publication will not consume additional sudo calls.
- Certbot failure:
- No retry loop, second certificate request, or hidden fifth sudo invocation.
- Leave an HTTP-only dual-host vhost and record
TLS pending; if the certbot operation partially changes the site, retain or restore the staged HTTP configuration within the same authorized invocation. - The owner may continue the fourth step so the HTTP application can serve. HTTP reachability is an operational fallback, not completed HTTPS publication.
- Any later privileged recovery beyond this budget requires a new owner decision; it is not implicit authority to alter another unit, site, or runtime.
Read-only fences
- Fleet:
- Every sibling project remains read-only, including
sflw,svelte-chat,bits,airi,iconmania,click2punch, andwrdp. - Direct imports may read permitted source graphs. Where no component file exists, attributed adaptations will be authored inside stbk.
- No writes to sibling source, manifests, lockfiles, installed dependencies, generated configuration, application state, or service definitions.
- Every sibling project remains read-only, including
- Operator configuration:
- No changes to home configuration, global OMP state, package-manager configuration, runtime installation, or unrelated service/vhost files.
- The four owner-only deployment operations above are the complete privileged exception, not a general host-maintenance allowance.
- Quartz:
stbk/q5vault/is the plan source and is exposed through the existing wiki content-root symlink.- No direct or persistent changes will be made to Quartz engine source, shared wiki infrastructure, or other vaults. The existing locked
wikis/build.shworkflow may temporarily stage the stbk config and stylesheet in the engine tree and must restore the prior files on exit. - Wiki publication will run only through the shared
wikis/build.shworkflow. The script acquires its own shared lock; do not surround it with another independent acquisition of the same lock. The owner will perform the integrated publication after page authors have finished; no competing direct engine build or manual release-tree mutation. - The build shell will explicitly use a readable umask rather than inheriting a previous secret-writing shell’s restrictive permissions.
# Run from the development root; the script acquires its own shared build lock.
umask 022
./wikis/build.sh stbk --check-only
./wikis/build.sh stbkFailure modes and fallbacks
-
Composition ref fails to load:
- Check the referenced story index, preview HTML, assets, base paths, and frame-loading policy at
/bits/independently from the root manager. - Keep the separate instance directly browsable at
stbk.loca.zone/bits/and expose that route as the visible fallback. - Do not merge the bits stylesheet into fleet, duplicate its components into the root renderer, or call direct browsing proof of working composition. A failed ref remains an acceptance failure until repaired.
- Check the referenced story index, preview HTML, assets, base paths, and frame-loading policy at
-
Selected port becomes occupied:
- Apply the fenced substitution order; each substitute is ten above the previous candidate.
- Record the choice and stage matching server/unit and proxy values. Do not kill the occupying process, choose an undocumented endpoint, or add a second listener for bits.
- If no candidate remains available, stop with a deployment blocker. If a later race would require extra privileged changes after the four calls, report deployment pending rather than exceeding the budget.
-
Quartz build succeeds but nginx cannot read the release:
- A restrictive inherited umask can create an unreadable output tree despite a green build.
- Use the explicit umask before the shared workflow; inspect generated directory traversal and file readability, then request the actual published pages. A successful build command alone does not prove HTTP readability.
- Retain the previous publish target; recovery must use the established publication workflow rather than edits to the engine or unrelated release trees.
-
Rendered title or frontmatter leaks:
- Verify the rendered article title against each page’s frontmatter title and inspect the article beginning for literal YAML/frontmatter leakage outside intended code examples.
- Verify that wikilinks resolve to the five planned pages and that Mermaid fences become visible diagrams; a successful status code or a source file containing the expected title is insufficient.
- Block publication on a leaked header, raw wiki syntax, missing diagram, or incorrect title; repair the owned vault/configuration input through the existing workflow, not shared Quartz internals.
-
TLS issuance fails:
- Preserve the HTTP-only dual-host fallback and explicit pending state described in the privilege budget. Do not claim secure deployment or hide the failure behind a certificate retry loop.
-
Runtime or dependency compatibility fails:
- Report the exact package/runtime requirement and stop that build. Do not replace Node/Bun, force peer resolution, or mutate a sibling project’s lockfile to make the plan appear complete.
-
Static-server readiness or asset delivery fails:
- Observe the service’s actual listener and request both native Storybook entry points, their indexes, and representative assets through the application hostname.
- A running unit without working HTTP assets is not ready. Preserve the assembled output and failure evidence; do not substitute an empty landing page or development server for the specified static delivery.
-
Final hosting evidence:
- Both hostnames will be fetched through nginx; the app will be exercised in a browser at its public origin, including root composition and direct
/bits/navigation. - The wiki’s rendered content, not just HTTP status, will be inspected after the shared publish.
- Record the effective endpoint, TLS outcome, four-call deployment boundary, and unchanged-fleet comparison. These are future completion requirements, not results asserted by this plan.
- Both hostnames will be fetched through nginx; the app will be exercised in a browser at its public origin, including root composition and direct