Architecture Decisions
ADR-001 — Headless Bits UI with a hand-rolled skin
Status: accepted in source.
Context: The project must show Bits UI behavior rather than demonstrate a second component system. bits-ui is declared; daisyUI is not. src/app.css identifies Bits UI as headless and defines one small shared skin.
Decision: Use Bits UI for component behavior and composition, then apply the project’s Tailwind 4 tokens and btn, card, panel, input, chip, and muted utilities. Do not add daisyUI.
Why: A second pre-styled component layer would obscure which behavior comes from Bits UI and create a competing visual contract. The shared CSS keeps the showcase coherent while leaving each demo’s anatomy visible.
Consequence: Demo authors reuse the same skin and style state selectors locally only where the primitive requires them.
ADR-002 — Registry as showcase SSOT
Status: accepted in source.
Context: Sidebar order, component metadata, previous/next links, upstream documentation links, and page routes must agree. Filesystem discovery alone does not carry category order or blurbs.
Decision: Keep those fields in src/lib/showcase/registry.ts, derive lookups and navigation from it, and require every component route slug to have one registry entry.
Why: One ordered data source prevents each shell, sidebar, and route from maintaining a divergent catalog.
Consequence: The generated component catalog follows the registry exactly, including its current 46-entry count.
ADR-003 — Browser relay instead of a server-side LLM key
Status: accepted integration contract and live browser round trip verified.
Context: The intended agent already operates through the OMP browser relay. The application dependency set has no server-side LLM SDK, and the serialisable BuilderOp vocabulary already defines a narrow edit boundary.
Decision: Expose version 1 of window.bitsBuilder in the builder page. The OMP agent reads messages and state, submits operations, and writes transcript replies through that surface. Do not put an LLM provider key or model client in the application server.
Why: The browser relay lets the user-visible session and agent share one reactive store and one mutation result without introducing another credential-bearing service path.
Consequence: The application owns deterministic state, persistence, rendering, and export. The external agent owns language interpretation. The production browser round trip verified that boundary.
ADR-004 — Dedicated application port 51500
Status: verified in production.
Context: deploy/bits.service sets HOST=127.0.0.1 and PORT=51500; deploy/bits.nginx.conf targets that same loopback upstream.
Decision: Reserve port 51500 for the application runtime and keep the Node listener off the public interface.
Why: A fixed, project-specific port gives the service and ingress configuration one unambiguous target.
Consequence: bits.service is active on 127.0.0.1:51500; nginx proxies the public application host to that loopback listener. The receipt is in Operations.
ADR-005 — adapter-node with systemd supervision
Status: verified in production.
Context: @sveltejs/adapter-node is declared, vite.config.ts passes adapter() to SvelteKit, and deploy/bits.service defines the long-running Node process and hardening policy. The built server is installed and active under systemd.
Decision: Produce adapter-node output and run it through the source-controlled systemd unit when deployment is performed.
Why: The adapter produces a standalone Node server boundary suitable for explicit environment and process supervision. systemd supplies restart and lifecycle control.
Consequence: The build artifact, unit identity, service user, environment, active state, listener, and startup journal were verified and recorded in Operations.
ADR-006 — Wiki as project SSOT
Status: authored, published, and live-verified.
Context: The showcase and builder have contracts that span code, browser integration, and deployment. A live site alone does not explain which source owns each behavior, while a free-form wiki can drift.
Decision: Keep the companion Quartz vault next to the project and derive exact tables and type excerpts from repository sources. Separate source facts from deployment receipts, and mark aspirational operations as pending.
Why: This gives maintainers one navigable map while preserving code as the authority for machine-consumed contracts.
Consequence: Registry tables and type excerpts must be regenerated or checked after source changes. Publication remains separate from application health; the production receipts are maintained in Operations.