Architecture

Module boundaries, dependency rules, and layered structure of the BodyMetrics codebase.

Overview

BodyMetrics separates concerns across six layers: UI coordination, rendering, domain facade, application workflows, business rules, and localization. Each layer has strict dependency rules to prevent coupling and make the codebase easy to evolve independently.

Layered Structure

Layer 1 — UI and Navigation

FileResponsibility
source/BodyMetricsView.mcMode coordinator — owns mode transitions, selection state, transient editor state, feedback badges, and renderer dispatch
source/BodyMetricsInputDelegate.mcTranslates hardware and touch input into state transitions
source/BodyMetricsMenuView.mcManages custom menus, sub-menus, and navigation delegates

The view does not read from storage directly. All data access goes through the Domain facade.

Layer 2 — Rendering

FileResponsibility
source/renderers/BodyMetricsSummaryDetailRenderer.mcDraws Summary and Detail screens
source/renderers/BodyMetricsWizardRenderer.mcDraws Profile/Measurement/Target wizard screens
source/renderers/BodyMetricsInfoTargetDeltaRenderer.mcDraws Info and Target Delta screens
source/renderers/BodyMetricsTrendRenderer.mcDraws the historical trend chart
source/renderers/RendererCommon.mcShared drawing utilities (text wrap, fit, draw centred, geometry)
source/BodyMetricsQrcodeView.mcFull-screen QR code view

Renderers receive a rendering-ready model dictionary and must not read from storage or mutate application state.

Layer 3 — Domain Facade

source/BodyMetricsDomain.mc is the compatibility surface consumed by the view. It coordinates use cases, policies, locale, and trend cache without duplicating presentation logic.

Layer 4 — Application Workflows (Use Cases)

FileResponsibility
source/usecases/BodyMetricsMeasurementsUseCase.mcManages measurements, editable fields, and derived values
source/usecases/BodyMetricsProfileUseCase.mcManages user profile and Garmin data merge
source/usecases/BodyMetricsTargetsUseCase.mcManages user targets and target fallback
source/usecases/BodyMetricsTrendUseCase.mcManages history and trend workflows
source/usecases/BodyMetricsResetUserDataUseCase.mcManages full reset and related invalidation

Use cases may depend on storage, services, and policies — but must not import view classes or rendering helpers.

Layer 5 — Business Rules and Services

FileResponsibility
source/policies/BodyMetricsClassificationPolicy.mcClassifies metrics into colour zones
source/policies/BodyMetricsThresholdFactory.mcGenerates thresholds per metric and profile
source/policies/BodyMetricsHealthCalculators.mcPure BMI, BMR, and muscle calculations
source/BodyMetricsHistory.mcPersists historical snapshots
source/BodyMetricsDataProvider.mcPersists current measurements
source/BodyMetricsTargets.mcPersists custom targets
source/BodyMetricsGarminProfile.mcReads Garmin UserProfile (weight, etc.)
source/trend/BodyMetricsTrendCacheService.mcPresentation cache for trend windows

Policies must remain side-effect free.

Layer 6 — Localization

FileResponsibility
source/BodyMetricsLocale.mcRuntime lookup adapter (only public locale interface)
source/i18n/BodyMetricsLocaleCatalog.mcMultilingual translation catalog (IT, EN, FR, ES)
source/i18n/BodyMetricsLocaleValidator.mcCompleteness validator for development

Dependency Rules

View  ──────────→  Domain  ──────→  UseCases  ──→  Storage / Services
  │                   │                              │
  └──→  Renderers      └──────────────────→  Policies
             └──→  RendererCommon
  • View may call Domain and Renderers; must not access storage directly.
  • Renderers depend only on RendererCommon and the render model.
  • UseCases depend on storage, services, and policies; never on views or renderers.
  • Policies are pure functions — no side effects, no I/O.
  • Locale lookups always go through BodyMetricsLocale; raw catalog access is only for the validator.

Global Helper Constraints

Two global functions are the single authoritative implementations across the entire codebase:

FunctionFilePurpose
round1Global()BodyMetricsDomain.mcOne-decimal rounding
fmt1Global()BodyMetricsDomain.mcOne-decimal string formatting

No file may define local equivalents. Similarly, the rendering utilities in RendererCommon.mc are the only authoritative implementations of text wrapping, width measurement, and centred text drawing.

Build Variants

VariantTargetLocalesStatus
Fullfr265IT, EN, FR, ES✅ Stable (v15)
LiteFR55, FR735XTEN only🔲 Planned

Validation Command

monkeyc -f monkey.jungle -d fr265 \
  -o /tmp/BodyMetrics-validation.prg \
  -y /path/to/bodymetrics-dev-key.pk8.der

See Also