Architecture
Native modules in development, production bundles in deployment
Local development loads the source as native ES modules (<script type="module">), so most UI work remains edit → reload. Hosted deployments run the Rolldown production build: it collapses the static startup graph into a hashed entry bundle while preserving feature-level lazy chunks.
That does not mean the repo has no tooling. The current repository uses npm for tests, type checks, Playwright, Vercel helpers, and a deploy-time catalog fetch. The practical development workflow is:
- Edit a file
- Reload the browser for quick local feedback
- Run the relevant checks before committing
MODULE_MAP.md records their direct imports. GitHub Actions owns the exhaustive browser and combined-coverage matrix.
File layout
Entry points
scripts/build-production.mjs; dynamically imported features remain separate lazy chunks.
main.js imports startup-loaded feature modules from app-feature-modules.js and starts startup-orchestrator.js. Foundation/privacy imports are grouped behind app-foundation-modules.js; Health & Data startup feature imports are grouped behind app-health-data-modules.js; Light & Sun startup feature imports are grouped behind app-light-sun-modules.js; import/export startup feature imports are grouped behind app-data-io-modules.js; AI/chat/settings startup feature imports are grouped behind app-ai-interaction-modules.js; UI shell startup feature imports are grouped behind app-ui-shell-modules.js. The orchestrator installs startup globals, the lazy EMF facade, app-wide event listeners, and the refresh callback, then registers the DOMContentLoaded sequence. Encryption unlock, meteo cache hydration, cross-tab broadcast, and folder backup setup are delegated to startup-foundation.js; profile migration, cache warmup, and active-profile data loading are delegated to startup-profile.js; wearable/OpenRouter callback routing lives in startup-oauth-callbacks.js; wearable runtime config/scheduler boot and non-blocking post-profile maintenance live in startup-maintenance.js; initial theme/sidebar/navigation/sync/changelog/header/chat/file-input UI bootstrap lives in startup-ui.js.
Trusted build-time extension boundary
app-extension-runtime.js supports one trusted extension selected while composing an edition build. Public and self-hosted builds install the core no-op adapter through app-extension-bootstrap.js. This is not a runtime plugin marketplace or a mechanism for loading arbitrary remote code.
The contract exposes bounded hooks for Settings and onboarding slots/actions, AI provider ownership/authorization/transport/options/errors, voice request authorization and playback policy, extra sync keys/encrypted prefixes/conflict resolution/post-apply refresh, and startup. An extension must have a stable ID. If an active extension owns an AI request but does not provide a successful authorization hook, the call fails closed before transport.
Marker catalog and placement boundary
The marker catalog uses an authoring → generated runtime → compatibility facade chain. Category modules underjs/marker-schema/ are the source of truth, scripts/build-marker-schema.mjs generates js/marker-schema.js, and long-lived consumers continue to import from js/schema.js. This keeps a large catalog maintainable without forcing a broad import-graph refactor.
Marker storage and display are separate boundaries. Profile values and companion metadata remain keyed by native category.markerKey; immutable gb:marker:* and custom:* IDs let marker-placement.js apply a per-profile visual category only after getActiveData() completes calculations and unit conversion. Renderers may use displayCategoryKey, but mutations must resolve through storageDotKey.
Units follow the same projection rule. unit-profiles.js maps canonical marker storage into the profile’s International/SI (EU), Australia/New Zealand (ANZ), or US display units after calculation and range resolution. Import review and manual entry convert compatible selected units back to canonical values. Individual renderers must not carry their own regional conversion tables.
The terminology registry follows a separate authoring and generation path. It is optional metadata and is intentionally outside startup, persistence, import/export, backup, sharing, and sync. See Marker model and category placement and Laboratory terminology registry.
Navigation and dashboard IA
The sidebar has three conceptual groups:- Home:
dashboard, the customizable cross-lens overview. - Lenses:
labs,genome,body,light,insight, andrecommendations.views-router.jsvalidates and dispatches these routes. Dashboard route/widget wiring is composed indashboard-view-composition.js, with the dashboard shell rendered throughdashboard-page-view.js; lab category routes render throughcategory-page-view.js; Labs, Genome, Body, Insight, and Recommendations pages are rendered throughlens-pages.js; shared lens page chrome and ordering live inlens-page-shell.js; the Light page shell lives inlight-page-view.js, while channel pills and drill-down panels live inlight-channel-view.js. - Tools: focused utilities such as compare dates, correlations, knowledge base, custom markers, and EMF assessment entry points.
recommendations route. The page aggregates data-linked recommendation candidates from Labs, Body, Light, and Genome signals, while product option rendering and affiliate disclosure remain owned by recommendations.js.
6-layer dependency graph
Modules in a higher layer may import from lower layers. Modules in the same layer must not import from each other — cross-layer calls within the same layer usewindow.fn() to avoid circular dependencies.
Circular dependency avoidance
The main tension is betweenviews.js (the compatibility/router facade) and modules like data.js and charts.js (which view modules depend on but which also need to trigger re-renders). Two mechanisms break cycles:
registerRefreshCallback(fn) in data.js — app-event-listeners.js registers the refresh function at startup, so data.js can trigger re-renders without importing views.js:
window.fn() calls — functions exposed via Object.assign(window, {...}) are callable from any module without creating an import edge:
External dependencies
Bundled locally undervendor/:
AI providers, Custom API, Local AI, xAI voice, and ElevenLabs voice are called directly from the browser. The dedicated compatibility service receives only policy-classified wearable, CAMS, NRAS, and credential-free public-page operations; it must never become a generic AI/voice proxy. The dedicated share service receives only browser-encrypted envelopes and metadata. Independent self-hosts keep their own same-origin compatibility endpoints.