fix: include exercise calories in diet adherence calculation
All checks were successful
CI / update (push) Successful in 3m55s

Adherence was comparing intake against the flat calorie goal, ignoring
burned workout calories. Now the per-day target is goal + exercise kcal.
Also expanded workout query from 7 to 30 days to cover the full
adherence window.
This commit is contained in:
2026-04-10 07:49:48 +02:00
parent 0ae16ddd6d
commit 89b3202dc5
3 changed files with 11 additions and 10 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "homepage", "name": "homepage",
"version": "1.23.2", "version": "1.23.3",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {

View File

@@ -22,7 +22,7 @@ export const GET: RequestHandler = async ({ locals }) => {
const thirtyDaysAgo = new Date(todayStart); const thirtyDaysAgo = new Date(todayStart);
thirtyDaysAgo.setUTCDate(thirtyDaysAgo.getUTCDate() - 30); thirtyDaysAgo.setUTCDate(thirtyDaysAgo.getUTCDate() - 30);
const [entries30d, goal, weightMeasurements, workoutSessions7d] = await Promise.all([ const [entries30d, goal, weightMeasurements, workoutSessions30d] = await Promise.all([
FoodLogEntry.find({ FoodLogEntry.find({
createdBy: user.nickname, createdBy: user.nickname,
date: { $gte: thirtyDaysAgo, $lt: todayStart }, date: { $gte: thirtyDaysAgo, $lt: todayStart },
@@ -34,7 +34,7 @@ export const GET: RequestHandler = async ({ locals }) => {
{ date: 1, weight: 1, _id: 0 } { date: 1, weight: 1, _id: 0 }
).sort({ date: 1 }).lean() as any[], ).sort({ date: 1 }).lean() as any[],
WorkoutSession.find( WorkoutSession.find(
{ createdBy: user.nickname, startTime: { $gte: sevenDaysAgo, $lt: todayStart }, 'kcalEstimate.kcal': { $gt: 0 } }, { createdBy: user.nickname, startTime: { $gte: thirtyDaysAgo, $lt: todayStart }, 'kcalEstimate.kcal': { $gt: 0 } },
{ startTime: 1, 'kcalEstimate.kcal': 1, _id: 0 } { startTime: 1, 'kcalEstimate.kcal': 1, _id: 0 }
).lean() as any[], ).lean() as any[],
]); ]);
@@ -121,9 +121,9 @@ export const GET: RequestHandler = async ({ locals }) => {
return bmr * neatMult; return bmr * neatMult;
} }
// Group workout kcal by date for the 7-day window // Group workout kcal by date for the 30-day window
const workoutKcalByDate = new Map<string, number>(); const workoutKcalByDate = new Map<string, number>();
for (const s of workoutSessions7d) { for (const s of workoutSessions30d) {
const key = new Date(s.startTime).toISOString().slice(0, 10); const key = new Date(s.startTime).toISOString().slice(0, 10);
workoutKcalByDate.set(key, (workoutKcalByDate.get(key) ?? 0) + (s.kcalEstimate?.kcal ?? 0)); workoutKcalByDate.set(key, (workoutKcalByDate.get(key) ?? 0) + (s.kcalEstimate?.kcal ?? 0));
} }
@@ -196,9 +196,10 @@ export const GET: RequestHandler = async ({ locals }) => {
yesterday.setUTCDate(yesterday.getUTCDate() - 1); yesterday.setUTCDate(yesterday.getUTCDate() - 1);
const totalDays = Math.round((yesterday.getTime() - firstDate.getTime()) / 86400000) + 1; const totalDays = Math.round((yesterday.getTime() - firstDate.getTime()) / 86400000) + 1;
const lower = dailyCalorieGoal * 0.9; const withinRange = dailyTotals.filter(d => {
const upper = dailyCalorieGoal * 1.1; const dayGoal = dailyCalorieGoal + (workoutKcalByDate.get(d.date) ?? 0);
const withinRange = dailyTotals.filter(d => d.calories >= lower && d.calories <= upper).length; return d.calories >= dayGoal * 0.9 && d.calories <= dayGoal * 1.1;
}).length;
adherenceDays = totalDays; adherenceDays = totalDays;
adherencePercent = Math.round(withinRange / totalDays * 100); adherencePercent = Math.round(withinRange / totalDays * 100);
} }

View File

@@ -295,8 +295,8 @@
{#if showAdherenceInfo} {#if showAdherenceInfo}
<div class="card-info-tooltip"> <div class="card-info-tooltip">
{lang === 'en' {lang === 'en'
? 'Percentage of days where calories eaten were within ±10% of your goal. Days without tracking count as misses.' ? 'Percentage of days where calories eaten were within ±10% of your goal (adjusted for exercise calories burned). Days without tracking count as misses.'
: 'Prozent der Tage, an denen die gegessenen Kalorien innerhalb von ±10 % deines Ziels lagen. Nicht erfasste Tage zählen als verfehlt.'} : 'Prozent der Tage, an denen die gegessenen Kalorien innerhalb von ±10 % deines Ziels lagen (bereinigt um verbrannte Trainings\u00ADkalorien). Nicht erfasste Tage zählen als verfehlt.'}
</div> </div>
{/if} {/if}
</div> </div>