Packages
The four workspace packages this app pulls in, what each settles, and the rule for when a component moves out of src/components and into the kit.
Four, and each one exists because a second app needed the same thing. Nothing here is a package because it felt reusable.
| Package | What this app takes from it |
|---|---|
@statshub/ui-web | Every shared primitive — button, table, sheet, the filter panel |
statshub-config | Feature flags and product metadata, including filters.bar |
statshub-i18n | The en / es / pt catalogs and the formatting helpers |
statshub-tooling | Build settings: allowedDevOrigins, the tracing root, the ESLint and PostCSS bases |
Where a component belongs
The split is ownership, not size:
src/composed/<board>/— parts only that board uses. Most components start and stay here.src/components/— used by two boards in this app.@statshub/ui-web— a second app would want it.adminimports this kit, so anything both apps need belongs in it.
Moving a component up a level is cheap; moving it back down after two apps have imported it is not. When it is genuinely unclear, leave it in the app — Add a UI component is the walkthrough for when it is not.
statshub-tooling is not optional
next.config.js composes withStatshubDefaults. That is what fills in
allowedDevOrigins from the running Tailscale daemon, so a phone on the tailnet
can load /_next/* chunks in dev. Bypass it and the page arrives with no
JavaScript and no styling, which reads as a broken app rather than a missing
setting.
What is deliberately not shared
The Chart.js setup, the nuqs filter keys and FeatureTemplate all live in
this app. They look shareable and are not: admin charts different shapes,
expo has no URL to put filter state in, and the template encodes this app's
three-region tool screen, which the native app does not have.
Conventions
The rules for writing code in the product site — where a filter goes, where state lives, what a new board must reuse, and how strings get translated.
Guides
The recipes for working in the product site — adding a board, adding a filter, putting a route on a phone, and getting a preview deployment.