refactor: split website and reusable UI package #32

Merged
vince merged 7 commits from codex/turbo-component-library into main 2026-06-20 05:52:08 +02:00
Showing only changes of commit 786a283f31 - Show all commits

View file

@ -0,0 +1,186 @@
# Turbo Component Library Migration Design
## Context
The current Dimension Lab website is a single Bun/Vite React package. It owns
the browser app, Bun production server, dashboard model, persistence, datasource
adapters, reusable UI components, Storybook, Playwright checks, and container
deployment from one `package.json`.
The UI components are already mostly generic and content-free under
`src/lib/ui`, but they are not reusable by another project because they live
inside the app package, depend on app path aliases, and share the app build,
test, and Storybook configuration. One file in that area,
`src/lib/ui/model-renderer.ts`, imports the Dimension Lab dashboard model and
therefore is an app adapter, not reusable component-library code.
The migration goal is to turn the repository into a Turborepo workspace where
the Dimension Lab website consumes a separate reusable React component package.
## Target Repository Shape
Use one application workspace and one component-library workspace:
```text
.
├── apps/
│ └── web/
│ ├── src/
│ ├── tests/
│ ├── drizzle/
│ ├── Containerfile
│ └── package.json
├── packages/
│ └── ui/
│ ├── src/
│ ├── .storybook/
│ ├── package.json
│ └── tsconfig.json
├── package.json
├── turbo.json
├── tsconfig.base.json
└── bun.lock
```
The root package is private and contains only workspace orchestration:
workspaces, Turbo scripts, shared dev dependencies where useful, and the lock
file. Runtime dependencies belong to the workspace that imports them.
## Package Ownership
`packages/ui` is a compiled React library named `@dimensionlab/ui`.
It owns:
- Reusable React components currently under `src/lib/ui/components`.
- UI CSS tokens and component styles.
- Theme helpers currently under `src/lib/ui/theme.ts`.
- Generic UI prop/data types currently under `src/lib/ui/types.ts`.
- Generic formatting helpers currently under `src/lib/ui/format.ts`.
- Generic Storybook stories and story fixtures.
- UI render tests, boundary tests, and Storybook inventory tests.
It must not import from the website app, the dashboard model, server modules,
database modules, datasource modules, or deployment files.
The library publishes explicit package exports:
- `@dimensionlab/ui` for component and type exports.
- `@dimensionlab/ui/styles.css` for the combined token/component CSS entry.
- Optional explicit subpath exports for future direct imports where useful.
The compiled output goes to `packages/ui/dist` and includes JavaScript,
declaration files, and copied CSS. The package stays private for now but is
structured so it can later be published or moved into another Dimension Lab repo
without taking the website runtime with it.
`apps/web` owns:
- The Vite React browser app.
- The Bun production server and API routes.
- Dashboard model, fixtures, schema, validation, and model migrations.
- Drizzle/SQLite persistence and checked-in SQL migrations.
- Datasource adapters and runtime dashboard loading.
- Agent dashboard configuration endpoint.
- The `dashboardDocumentToUiDashboard` adapter that maps the app model to UI
package props.
- Playwright e2e tests and deployment container.
## Why A Compiled Package
The component package should be compiled rather than a just-in-time source
package. This is slightly more setup, but it better fits reuse outside the
current app because consumers can import stable JavaScript and declarations
instead of relying on their bundler to transpile this repo's TypeScript source.
It also gives Turbo a cacheable `@dimensionlab/ui#build` task.
## Build And Task Graph
Root scripts delegate through Turbo:
- `bun run dev` runs the web dev server and any required dependency tasks.
- `bun run build` runs package builds in dependency order.
- `bun run check` runs TypeScript checks for all workspaces.
- `bun run test:unit` runs Vitest unit tests for all workspaces.
- `bun run build-storybook` builds Storybook from `packages/ui`.
- `bun run test:e2e` runs the web app Playwright suite.
- `bun run test:qa` is the full release gate.
`turbo.json` defines `build`, `check`, `test:unit`, `build-storybook`,
`test:e2e`, and `test:qa` tasks. Build outputs include `dist/**`,
`storybook-static/**`, and `build/**` as appropriate.
The web app depends on `@dimensionlab/ui` using Bun workspace syntax. The web
Vite config aliases `$lib` to `apps/web/src/lib`; the UI package should not use
that app alias.
## Storybook
Storybook moves with the component package. It should load
`@dimensionlab/ui/styles.css`, use React Vite Storybook, and keep the existing
generic story inventory. Environment-specific Dimension Lab labels, hostnames,
links, fallback values, and datasource names remain forbidden in package UI
source and stories.
The repository should no longer have a root Storybook tied to the web app.
## Deployment
The deployed website remains the same service from the outside:
- Production command remains `bun build/index.js` inside the runtime image.
- The container still exposes port `3000` and mounts `/data`.
- Runtime environment variables and database behavior remain unchanged.
The `Containerfile` moves to `apps/web/Containerfile` or remains root with
updated workspace-aware copy/build steps. The chosen layout must preserve the
existing Podman service contract used by `dimensionlab-website.service`.
## Testing Strategy
The migration must add or update tests that prove the new boundaries:
- The root package is a Bun workspace with `apps/*` and `packages/*`.
- The web app imports UI from `@dimensionlab/ui`, not from local copied
component files.
- `packages/ui` does not import from `apps/web`, `$lib/server`, `$lib/model`,
or any website runtime module.
- `dashboardDocumentToUiDashboard` lives in `apps/web` and is tested there.
- Storybook inventory is evaluated against `packages/ui`.
- The full QA gate still covers typecheck, unit tests, app build, Storybook
build, and Playwright desktop/mobile checks.
## Completion Criteria
The migration is complete only when current evidence proves all of these:
- Root `package.json` is a private workspace root with Turbo scripts.
- `turbo.json` exists and models the workspace task graph.
- The web application lives under `apps/web`.
- The reusable React component library lives under `packages/ui`.
- `packages/ui/package.json` is named `@dimensionlab/ui` and has compiled
exports for code, types, and CSS.
- The web app depends on `@dimensionlab/ui` through the workspace.
- Reusable components and Storybook have been removed from the web app package.
- App-specific model/server/database/datasource code has not moved into
`packages/ui`.
- `dashboardDocumentToUiDashboard` is outside the UI package.
- `bun run check` passes from the root.
- `bun run test:unit` passes from the root.
- `bun run build` passes from the root.
- `bun run build-storybook` passes from the root.
- `bun run test:e2e` passes from the root.
- The production container can still be built and run with the same service
contract.
## Migration Approach
Implement this on branch `codex/turbo-component-library` in focused commits:
1. Add the workspace/Turbo scaffolding and boundary tests.
2. Move UI code and Storybook to `packages/ui`.
3. Move the app runtime into `apps/web` and wire it to `@dimensionlab/ui`.
4. Move the model-to-UI adapter into the web app.
5. Update build, test, Playwright, Storybook, README, and container paths.
6. Run the full QA gate, push a ready PR, perform independent review, resolve
blockers, merge to `main`, and deploy only when checks and review are clean.