From 26f13c506480595b709f810a84f7869630e1cad4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Thu, 28 May 2026 22:20:51 +0200 Subject: [PATCH] feat(measurements): raise the series days cap to ten years The 365-day cap on /api/measurements/series rejected the iOS app's "Alle"-range request (days = 3650) with a 422, painting an error banner on every metric tile. Ten years matches the recurrence engine's hard cap and the medication course-window upper bound. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../measurements/series/__tests__/route.test.ts | 17 +++++++++++++++++ src/app/api/measurements/series/route.ts | 8 +++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/app/api/measurements/series/__tests__/route.test.ts b/src/app/api/measurements/series/__tests__/route.test.ts index eb83aaf38..421908782 100644 --- a/src/app/api/measurements/series/__tests__/route.test.ts +++ b/src/app/api/measurements/series/__tests__/route.test.ts @@ -116,6 +116,23 @@ describe("GET /api/measurements/series", () => { }; expect(body.data.points[0].secondary).toBeNull(); }); + + it("accepts the ten-year window (days=3650 — iOS 'Alle'-range)", async () => { + // v1.5.5 — the previous 365-day cap rejected the iOS app's + // "Alle"-range request with a 422, painting an error banner on + // every metric tile. Ten years matches the recurrence engine's + // hard cap and the medication course-window upper bound. + vi.mocked(getSession).mockResolvedValue(SESSION_OK as never); + vi.mocked(prisma.measurement.findMany).mockResolvedValue([] as never); + const res = await GET(req("kind=weight&days=3650")); + expect(res.status).toBe(200); + }); + + it("rejects a days value above the ten-year cap", async () => { + vi.mocked(getSession).mockResolvedValue(SESSION_OK as never); + const res = await GET(req("kind=weight&days=3651")); + expect(res.status).toBe(422); + }); }); describe("GET /api/measurements/series — 422 multi-issue (v1.4.43 W6)", () => { diff --git a/src/app/api/measurements/series/route.ts b/src/app/api/measurements/series/route.ts index 691b7a13e..95e7f2fba 100644 --- a/src/app/api/measurements/series/route.ts +++ b/src/app/api/measurements/series/route.ts @@ -38,7 +38,13 @@ const kindEnum = z.enum([ const querySchema = z.object({ kind: kindEnum, - days: z.coerce.number().int().min(1).max(365).optional().default(30), + // v1.5.5 — the 365-day cap rejected the iOS app's "Alle"-range + // request (days = 3650) with a 422, painting an error banner on + // every metric tile. Ten years matches the recurrence engine's + // nextOccurrenceAfter hard cap and the medication course-window + // upper bound, so the ceiling stays consistent across the surface + // area that the user can wire to a "show me everything" intent. + days: z.coerce.number().int().min(1).max(3650).optional().default(30), }); const KIND_TO_TYPE: Record, MeasurementType> = {