Architecture
TypeScript authoring and JavaScript runtime
Edit canonical.ts and .mts sources. TypeScript 7 emits ignored .js and .mjs siblings at the existing runtime paths. Local development loads these emitted native ES modules; production uses Rolldown to bundle the startup graph and retain lazy feature chunks. The browser does not load TypeScript directly.
Use Node.js 24. npm ci installs dependencies and compiles through prepare; npm run dev-server, npm test, and the production build/check commands also compile first. With a server already running, compile after source edits before reloading. Direct Node and Playwright commands need the same compilation step.
.js and .mjs specifiers in source imports, dynamic imports, worker URLs, HTML scripts, and runtime commands. For example, import './data.js' in profile.ts resolves to the authored TypeScript for checking and to emitted JavaScript at runtime. Do not edit or commit emitted siblings. Third-party vendor bundles retain their own source formats.
The production and test compiler projects are separate and strict. The app, server, worker, and editor projects also retain their environment-specific safety checks; migration completion does not permit weakened flags or suppression comments. See the app’s source and compiler contract.
Source modules remain the ownership boundary. Regenerate MODULE_MAP.md when modules or imports change. GitHub Actions owns the exhaustive browser and combined-coverage matrix.
File layout
Entry points
js/main.ts; the HTML keeps the emitted js/main.js URL. The hosted artifact rewrites it to the hashed Rolldown entry generated by scripts/build-production.mts.
main.ts installs extension, foundation, cold health/Light loaders, UI shell hooks, and delegated shell actions, then calls startApp() from startup-orchestrator.ts. Startup installs global event and refresh wiring, initializes encryption/storage foundation and profile data, runs post-profile maintenance and OAuth callbacks, renders the UI, invokes the edition startup hook, and restores pending import review state. It reports failure without silently replacing unreadable profile data.
Feature loaders keep expensive behavior out of the cold graph. Health modules load according to route and persisted data; chat-loader.ts loads app-ai-interaction-modules.ts on first use. Import, export, settings, sharing, and EMF have their own loader or runtime boundaries. emf-runtime.ts receives its module loader and host callbacks through app-shell-hooks.ts and loads the EMF module and stylesheet together. The composition modules remain useful grouping boundaries; they are not all eager imports of main.ts.
Trusted build-time extension boundary
app-extension-runtime.ts 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.ts. 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 authored TypeScript → generated TypeScript → emitted JavaScript chain. Category modules underjs/marker-schema/ are the source of truth, scripts/build-marker-schema.mts generates js/marker-schema.ts, and long-lived consumers continue to use the js/schema.ts compatibility facade through its ./schema.js runtime specifier. 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.ts 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.ts 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.tsvalidates and dispatches these routes. Dashboard route/widget wiring is composed indashboard-view-composition.ts, with the dashboard shell rendered throughdashboard-page-view.ts; lab category routes render throughcategory-page-view.ts; Labs, Genome, Body, Insight, and Recommendations pages are rendered throughlens-pages.ts; shared lens page chrome and ordering live inlens-page-shell.ts; the Light page shell lives inlight-page-view.ts, while channel pills and drill-down panels live inlight-channel-view.ts. - 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.ts.
Dependency direction
npm run architecture:check enforces zero cycle ceilings and the repository’s explicit boundary rules. The architecture contract owns these rules; the generated module map records actual imports. The module reference groups ownership areas rather than defining a second set of layer restrictions.
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.