mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-10 21:32:18 +00:00
The water quick-add validated calendar realism but never the upper day bound the batch route applies, so a far-future day was accepted and — every read filters `day >= since` with no ceiling — became the permanent latest day on the settings card and the dashboard tile. Hoist the bound into one shared helper both routes use. `mode: "add"` bounded a single request to the catalog's plausible daily max but nothing across requests, so repeated quick-adds drove the stored total arbitrarily high while the batch route enforced the same cap strictly. Clamp after the increment so the write stays atomic. Thiamin's cap sat at exactly 1000 mg while its PRI is exactly 1.0 mg, so a microgram-read-as-milligram sample landed on precisely the cap and the `>` comparison let it through. 500 still clears any real supplement dose. NutrientIntakeDay was in no export path, which contradicted the schema's own reason for denormalising the unit column. Carry it in the full backup with its unit and source — source is part of the composite key, so without it a restore cannot tell a manual entry from a synced day total.
21 lines
989 B
TypeScript
21 lines
989 B
TypeScript
/**
|
|
* Shared upper day bound for the nutrient write paths.
|
|
*
|
|
* `NutrientIntakeDay.day` is a local `YYYY-MM-DD` key, so the server cannot
|
|
* simply compare it against the UTC date: a client in the most-ahead IANA zone
|
|
* (UTC+14) is legitimately already on "tomorrow" relative to UTC. Two days of
|
|
* slack covers every real zone and still rejects a key that cannot be a local
|
|
* day at all.
|
|
*
|
|
* The batch route carried this bound privately while `POST /api/nutrients/water`
|
|
* validated calendar realism only — so a manual write could land a `2999-01-01`
|
|
* row, and since every read filters `day: { gte: since }` with no upper bound,
|
|
* that row became the permanent `latestDay` on the settings card and the
|
|
* permanent `lastSeenAt` on the dashboard water tile. Both routes now share
|
|
* this one bound.
|
|
*/
|
|
export function maxAcceptableNutrientDay(now: Date): string {
|
|
const limit = new Date(now.getTime() + 2 * 24 * 60 * 60 * 1000);
|
|
return limit.toISOString().slice(0, 10);
|
|
}
|