Server-side step calorie calculation#991
Server-side step calorie calculation#991BryceKrispiess wants to merge 7 commits intoCodeWithCJ:mainfrom
Conversation
…across web and mobile Mobile was using a hardcoded `steps * 0.04` approximation while the server and web frontend used the more accurate stride-based formula: distance(km) × weight(kg) × 0.4 This caused mobile to report nearly double the step calories for a typical user (400 kcal vs ~200 kcal for 10,000 steps at 70kg/175cm). - Server: expose `stepCalories` (already computed correctly) in the `/api/dashboard/stats` response - Mobile: add `dashboardApi.ts` + fetch `stepCalories` from server in `useDailySummary`; thread value through `DailySummary` type and `calculateEffectiveBurned` (removing the local `stepsToCalories` function) Any future fix to the step calorie formula now only needs to happen once, on the server. https://claude.ai/code/session_0199DHyvSiYcgKVWpJ2cj7Wy
…ocessing-Lg5BQ feat: compute step calories server-side to ensure consistent results …
The previous migration (20260323122741) added steps only to exercise_entries, but exerciseEntryHistoryService.ts also selects steps from exercise_preset_entries when building preset workout sessions, causing a runtime crash: "column \"steps\" does not exist" https://claude.ai/code/session_0199DHyvSiYcgKVWpJ2cj7Wy
…ocessing-Lg5BQ fix: add missing steps column to exercise_preset_entries
- dashboardApi.test.ts: covers fetchDashboardStats GET request, response shape (including stepCalories), and error handling - useDailySummary.test.ts: mock fetchDashboardStats, assert stepCalories is included in the summary, and verify graceful fallback to 0 when the dashboard stats endpoint fails https://claude.ai/code/session_0199DHyvSiYcgKVWpJ2cj7Wy
…ocessing-Lg5BQ test: add tests for server-side step calorie calculation
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly improves the consistency and accuracy of step calorie calculations by centralizing the logic on the server. Previously, client-side calculations could lead to discrepancies across different platforms. By moving this computation to the backend, the system now provides a single, authoritative source for step-related calorie burn, leveraging user-specific weight and height for more precise results. This change streamlines data handling and ensures a more reliable user experience regarding fitness tracking. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces server-computed stepCalories to replace the client-side stepsToCalories approximation. This involves adding a new dashboardApi to fetch these statistics, updating the useDailySummary hook to integrate this data, and modifying the calculateEffectiveBurned function to prioritize this more accurate stepCalories value. A review comment suggests improving type safety and consistency in the useDailySummary hook's error handling for fetchDashboardStats by returning a full default DashboardStats object on failure.
| fetchFoodEntries(date), | ||
| fetchExerciseEntries(date), | ||
| fetchWaterIntake(date).catch(() => ({ water_ml: 0 })), | ||
| fetchDashboardStats(date).catch(() => ({ stepCalories: 0 })), |
There was a problem hiding this comment.
For better type safety and consistency with how other failed fetches are handled (like fetchWaterIntake), it's a good practice for the .catch block to return an object that conforms to the DashboardStats interface, even if it's just a default/fallback version. This makes the code more robust for future modifications where other properties of dashboardStats might be used.
A default DashboardStats object could be defined and reused, perhaps in dashboardApi.ts.
| fetchDashboardStats(date).catch(() => ({ stepCalories: 0 })), | |
| fetchDashboardStats(date).catch(() => ({ eaten: 0, burned: 0, remaining: 0, goal: 0, net: 0, progress: 0, steps: 0, stepCalories: 0, bmr: 0, unit: 'kcal' })), |
There was a problem hiding this comment.
The extra zeroed fields don't matter since the hook only reads stepCalories anyways. There's no real type issue if the shape allows partials.
|
Steps shouldn't be in preset table. |
|
@CodeWithCJ Will do in the future. I had talked with @apedley about helping out with some of the app development. I know he had some tweaks for this so I moved to draft for now. |
|
@CodeWithCJ should the server endpoint be fixed to query the right table, or should steps be removed from |
apedley
left a comment
There was a problem hiding this comment.
The core idea and direction is good, but there are some problems I've made comments for. Also:
- dashboard fetch is done in useDailySummary instead of it's own query so theres no way to invalidate or refresh just those stats.
- the big one: we now call 10 api endpoints for the dashboard screen and displaying the same data. if this is meant to consolidate the api hits, then more data will need to be added to the /api/dashboard/stats endpoint and we can remove the others. What is interesting about that endpoint though is it's not used for any of our code, just an external dashboard integration. so just verify how complete/correct the data it returns is. the other option is to add
stepCaloriesto one of the existing api calls
| unit: string; | ||
| } | ||
|
|
||
| export const fetchDashboardStats = async (date: string): Promise<DashboardStats> => { |
There was a problem hiding this comment.
should encodeURIComponent the date to be sure
| @@ -0,0 +1,22 @@ | |||
| import { apiFetch } from './apiClient'; | |||
|
|
|||
| export interface DashboardStats { | |||
There was a problem hiding this comment.
There is a shared package (just for web and mobile right now) in the /shared/src/ folder that uses zod to validate and then infer types. We are moving new code to that pattern
|
|
||
| beforeEach(() => { | ||
| jest.resetAllMocks(); | ||
| (globalThis as any).fetch = mockFetch; |
There was a problem hiding this comment.
the actual implementation uses apiFetch in apiClient.ts so this isn't testing the real code path
Tip
Help us review and merge your PR faster!
Please ensure you have completed the Checklist below.
For Frontend changes, please run
pnpm run validateto check for any errors.PRs that include tests and clear screenshots are highly preferred!
Description
Server-side step calorie calculation
Previously, step calories were computed client-side on each platform (web/mobile)
independently, leading to inconsistencies. This moves that calculation to the server.
Changes:
Server
DashboardService.js: GET /api/dashboard/stats now queries pedometer dataand computes stepCalories using the user's weight/height-based calorie formula,
returning it alongside the existing dashboard fields.
Mobile
dashboardApi.ts: New API client that fetches /api/dashboard/stats.Mobile
useDailySummary.ts: Hook now fetches stepCalories from the server andincludes it in the summary. Gracefully falls back to 0 if the endpoint fails.
Mobile
calculations.ts: calculateEffectiveBurned updated to acceptserver-provided stepCalories instead of computing it locally.
Tests: New
dashboardApi.test.tscovers the fetch function (request shape, responseparsing, error handling).
useDailySummary.test.tsupdated to mockfetchDashboardStats and assert stepCalories flows through correctly, including the
failure fallback.
Related Issue
PR type [X ] Issue [ ] New Feature [ ] Documentation
Linked Issue: #
Checklist
Please check all that apply:
pnpm run validate(especially for Frontend).en) translation file (if applicable).rls_policies.sqlfor any new user-specific tables.Screenshots (if applicable)
Before
[Insert screenshot/GIF here]
After
[Insert screenshot/GIF here]