feat(measurements): surface that the entry timestamp is editable for backdating

The add form already defaults the timestamp to now and accepts any earlier
instant — the plausibility bound and the picker's max both block the future —
but many users never notice they can change it. Add a one-line hint under the
date/time field so logging a past reading is discoverable, and pin the
manual-create contract with a guard asserting the single POST schema strips an
externalId (the stats:-prefix overwrite stays batch-scoped).
This commit is contained in:
Marc-André Bombeck committed 2026-06-14 23:28:36 +02:00
1 parent fbdcb31202
commit f0a14ac0b4
2 files changed
+26

No files matched your search

@@ -481,6 +481,12 @@ export function MeasurementForm({
aria-invalid={!!error || undefined}
aria-describedby={errorDescriptor}
/>
{/* v1.17.1 — surface that the timestamp is editable. The picker
already defaults to now and accepts any earlier instant; many
users never notice they can backdate a reading. */}
<p className="text-muted-foreground text-xs">
{t("measurements.timestampBackdateHint")}
</p>
</div>
<div className="space-y-2">
@@ -206,6 +206,26 @@ describe("measurement validation", () => {
expect(parsed.data.deviceType).toBeUndefined();
}
});
// v1.17.1 — the `stats:`-prefix overwrite contract is deliberately
// batch-scoped. The single manual POST must never accept an
// `externalId`, which would open a client-controlled overwrite vector
// on the `(userId, type, source, externalId)` unique key. The schema
// strips it (no passthrough), so the parsed value never carries one.
it("does not surface an externalId on the manual create schema (overwrite contract)", () => {
const parsed = createMeasurementSchema.safeParse({
...validBase,
type: "WEIGHT",
value: 82,
externalId: "stats:HKQuantityTypeIdentifierBodyMass:2026-04-27",
});
expect(parsed.success).toBe(true);
if (parsed.success) {
expect(
(parsed.data as Record<string, unknown>).externalId,
).toBeUndefined();
}
});
});
// v1.4.37 W7c — list-view "one row per day" mode for cumulative