feat: Withings weight sync + dedicated Biometrics category UX#96
feat: Withings weight sync + dedicated Biometrics category UX#96marian001 wants to merge 1 commit intoelkimek:mainfrom
Conversation
|
@marian001 is attempting to deploy a commit to the elkimek's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
Thanks for the PR Marian, I can't merge it right now as I'm in process of rewriting getbased to V2 (Tauri/TypeScript/Svetle) and these integration will need a proper system, can't be just glued into it. Will look into this ASAP once V2 is stable and released. |
elkimek
left a comment
There was a problem hiding this comment.
Thanks for this Marian — solid work, especially the biometrics-view module and the OAuth flow structure. Sorry for the delayed review (V2 rewrite was abandoned, back to v1).
I've done a thorough code review. The biometrics category view is great UX and something I want to ship. However, there are some issues with the Withings integration that need addressing, plus an architectural consideration.
Security issues (must fix)
- Client secret + tokens stored in plaintext localStorage — needs encryption via
encryptedSetItem/SENSITIVE_PATTERNSincrypto.js, consistent with how all other API keys are stored - Access token in URL query string (line 166) — leaks to browser history/logs. Use
Authorization: Bearerheader instead - OAuth state uses
Math.random()— not cryptographically secure. Usecrypto.getRandomValues()for CSRF protection - No
meastypefilter on API call — fetches all measurement types, filters client-side. Should request only weight (meastype=1) from the server
Functional bugs
- Delete filter logic is inverted (line 252) — keeps Withings rows and deletes manual ones. The condition needs to be flipped
- Weight stored in display units — should always store raw kg with
unit: 'kg', convert at display time. Currently bakes the unit system at sync time
Architecture: wearable adapter system
Per the discussion in #5, I want to build a proper wearable adapter system (similar to adapters.js for specialty labs) before merging individual integrations. The core issue is that wearable APIs need server-side OAuth token exchange — putting the client secret in the browser isn't safe.
The plan is:
js/wearables.js— shared OAuth flow, credential storage (encrypted), sync scheduling, settings UI generationjs/wearables/withings.js— adapter config (endpoints, scopes, data mapping)- OAuth token exchange handled via the relay (users who want wearables likely already self-host one for sync)
Your Withings code would become the first adapter in this system. The biometrics-view.js is mostly ready to merge as-is — it's the rendering layer that any wearable adapter feeds into.
What I'd suggest
- I'll merge
biometrics-view.js(the category view) separately — it's good and needed - I'll build the wearable adapter framework based on your Withings implementation as the reference
- Your OAuth + sync code becomes the Withings adapter, with the security fixes above
Would you be open to that approach? Happy to collaborate on the adapter system.
|
To clarify my review above — I'm not merging wearable integrations right now. I need to build a proper wearable adapter system first (per #5), which will take time. Your code is a useful reference for when I get to it. Thanks again for the contribution. |
Summary
This PR adds a first wearable integration via Withings and introduces a dedicated Biometrics category UX for time-series biometrics.
It implements OAuth connection + sync from Withings, imports weight data into the existing biometrics structure, and surfaces biometrics as a first-class category in the sidebar with standard chart/detail interactions.
Closes the immediate use case discussed in #5 around wearables integration by shipping an initial, practical scope.
What was added/changed
1) Withings integration (initial scope: weight only)
js/withings-weight.jsuser.metricsscope)measure/getmeasimportedData.biometrics.weightlastupdatejs/main.js2) Settings UI for Withings
js/settings.js3) Biometrics as dedicated category + UX parity improvements
js/biometrics-view.jscreateLineChart(...)(axes/tooltips/grid), not mini custom sparkline charts1M / 3M / 9M / All) applied across all biometrics charts4) Navigation and routing updates
js/nav.jsjs/views.jsnavigate('biometrics') -> showBiometrics()How it works
Data model
state.importedData.biometricsstructure:weight[]with{ date, value, unit, source }bp[]with{ date, sys, dia, source }pulse[]with{ date, value, source }source: 'withings'rows for weightsource: 'manual'Sync behavior
lastupdate)How to use Withings integration
Optional:
Scope note / future extension
This PR intentionally ships weight-only import for now, even though Withings API exposes additional measurements. The integration path and UI scaffolding are now in place, so additional types (e.g., blood pressure, heart rate, body composition metrics) can be added incrementally in follow-up PRs.
Related issue
Files changed
js/main.jsjs/nav.jsjs/settings.jsjs/views.jsjs/withings-weight.js(new)js/biometrics-view.js(new)