chore(release): v1.28.44 — loose ends: broken link, API contract, module guards

From the campaign's dead-code + code-health audits (grep-verified; the
custom-metrics query-key finding was verified-false and excluded):

- sleep-overview empty-state CTA linked to /settings/devices, not a valid
  settings slug (dynamicParams=false → 404). Repointed to
  /settings/integrations (where every device OAuth callback already lands).
- six live, iOS-consumed routes were absent from docs/api/openapi.yaml —
  auth/check-user, insights/cards, integrations/healthkit (GET+PATCH),
  measurement-categories, medications/intake/bulk, mood-entries/bulk —
  registered in the Zod OpenAPI registry mirroring each handler's real shape.
- mood/labs/medications module pages lacked the redirect-when-off self-guard
  their siblings have; added, mirroring cycle/achievements exactly.

No migration. Verifier REJECTED the custom-metrics bare-key finding (they are
invalidateQueries prefix filters, not colliding useQuery keys).
This commit is contained in:
Marc-André Bombeck committed 2026-07-16 04:59:27 +02:00
1 parent 8b6024f0d7
commit cd0fbddd1d
17 files changed
+1433 -16

No files matched your search

@@ -0,0 +1,39 @@
/**
* The sleep-overview empty-state CTA must point at a REAL settings slug.
* It previously linked to `/settings/devices`, which is not in
* `SETTINGS_SECTION_SLUGS`, so the dynamic `[section]` route (dynamicParams
* = false) calls `notFound()` → a hard 404 dead-end. This pins the href to
* the `integrations` slug (where every device OAuth callback lands) and
* guards against a regression to any non-existent slug.
*/
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { isSettingsSectionSlug } from "@/components/settings/section-slugs";
describe("sleep-overview empty-state CTA href", () => {
it("links to /settings/integrations (a real settings slug)", () => {
const source = readFileSync(
join(process.cwd(), "src/components/insights/sleep-overview.tsx"),
"utf8",
);
const match = source.match(/href="\/settings\/([a-z-]+)"/);
expect(
match,
"expected a /settings/<slug> href in the sleep overview",
).not.toBeNull();
const slug = match![1];
expect(slug).toBe("integrations");
expect(isSettingsSectionSlug(slug)).toBe(true);
});
it("never links to the non-existent /settings/devices slug", () => {
const source = readFileSync(
join(process.cwd(), "src/components/insights/sleep-overview.tsx"),
"utf8",
);
expect(source).not.toContain("/settings/devices");
});
});
+4 -4
View File
@@ -66,9 +66,9 @@ function SleepStageStackedBar(
*
* Empty state: no SLEEP_DURATION rows yet → render the "Apple Health
* sync is coming in v1.5" message with a deep-link to Settings →
* Devices so the user can prepare. We do NOT render any of the three
* blocks in that case — half-rendered empty cards would be worse than
* a single clean CTA.
* Integrations so the user can connect a sleep source. We do NOT render
* any of the three blocks in that case — half-rendered empty cards would
* be worse than a single clean CTA.
*/
interface SleepAnalyticsSummary {
@@ -111,7 +111,7 @@ export function SleepOverview() {
description={t("insights.sleep.empty.description")}
action={
<Button size="sm" variant="outline" asChild>
<Link href="/settings/devices">
<Link href="/settings/integrations">
{t("insights.sleep.empty.action")}
</Link>
</Button>