Answer the native client's open server asks

- Publish timezone, glucoseUnit and a features block on the account
  payload; glucoseUnit reads as the closed pair the contract names, and
  features.trackIntake tells a separately released client that
  medications take the record-only switch.
- Refuse a new dose for a record-only medication with
  medication.intake.notTracked on every dose-writing route; the bulk
  route reports it per entry as intake_not_tracked, and correcting an
  already resolved event stays open.
- Answer passkey sign-in failures by name instead of a 500:
  passkey.challenge.expired, passkey.unknown, passkey.response.invalid
  and passkey.verification.failed, each with an audit row.
- Carry one account-wide adherence figure in meta.aggregate on the
  batched compliance read, weighted by expected doses, and accept
  ?days=30|60|90|180|365 for a report window.
- Accept ?days=30|90|180|365 on the mood insights read so stability
  covers the period shown, and name the window it covers.
- Keep only the reminder that announces a dose off APNs when the phone
  owns medication reminders; follow-ups for a dose still open are
  pushed again, marked by a followUp flag the reminder cron sets.
- Document which batch validation issues belong to an entry and pin it
  with a test that splits and resends a batch; publish rejectedFields
  items as ValidationIssue.
This commit is contained in:
Marc-André Bombeck committed 2026-10-08 10:32:11 +02:00
1 parent 7bcb6f71d9
commit bb563b6506
50 files changed
+1789 -142

No files matched your search

@@ -197,6 +197,32 @@ describe("per-user timezone — Pacific/Auckland end-to-end", () => {
}
});
// The fields a native client decides on, enumerated in `AccountPayload`:
// the unit as the closed pair the contract names (a restored backup can
// write anything into the free-text column), and the capability flags.
it("GET /api/auth/me publishes the glucose unit as the closed pair and the server features", async () => {
const user = await seedAucklandUser();
const prisma = getPrismaClient();
const { GET } = await import("@/app/api/auth/me/route");
await prisma.user.update({
where: { id: user.id },
data: { glucoseUnit: "mmol/L" },
});
let body = (await (await GET()).json()) as {
data: { glucoseUnit: string | null; features: Record<string, unknown> };
};
expect(body.data.glucoseUnit).toBe("mmol/L");
expect(body.data.features).toEqual({ trackIntake: true });
await prisma.user.update({
where: { id: user.id },
data: { glucoseUnit: "mmol" },
});
body = (await (await GET()).json()) as typeof body;
expect(body.data.glucoseUnit).toBeNull();
});
it("PUT /api/auth/me/timezone rejects an invalid IANA zone with 422", async () => {
await seedAucklandUser();