Review

AetherGrow bay detail: slim select + defer telemetry

Cellar techs on the AetherGrow rooftop greenhouse open bay detail dozens of times per shift. The loader was awaiting a full Prisma row (nutrient recipes, vendor notes, photo blobs) and a 24h Timescale telemetry series before the route could paint. Return only the header/control-strip fields via select, and defer the slow sparkline series so the shell streams immediately.

RemixTier 3remixloaderdeferoverfetch

Click a line to flag it, pick one or more labels, then submit. If the change looks correct, approve it.

app/routes/bays.$bayId.tsx+20-4
11import type { LoaderFunctionArgs } from "@remix-run/node";
22import { defer } from "@remix-run/node";
33import { Await, useLoaderData } from "@remix-run/react";
44import { Suspense } from "react";
55import { db } from "~/db.server";
66import { loadBayTelemetry } from "~/services/telemetry.server";
77import { BayHeader, TelemetrySparkline } from "~/components/bay";
88
99export async function loader({ params }: LoaderFunctionArgs) {
1010 const bayId = params.bayId!;
11- const bay = await db.hydroBay.findUniqueOrThrow({ where: { id: bayId } });
12- const telemetry = await loadBayTelemetry(bayId, { hours: 24 });
13- return json({ bay, telemetry });
11+ // Header + control strip only — skip recipes, notes, photo blobs.
12+ const bay = await db.hydroBay.findUniqueOrThrow({
13+ where: { id: bayId },
14+ select: {
15+ id: true,
16+ crop: true,
17+ phase: true,
18+ ecTarget: true,
19+ phTarget: true,
20+ lastHarvestAt: true,
21+ },
22+ });
23+ // Do not await: stream the 24h series after the shell paints.
24+ const telemetry = loadBayTelemetry(bayId, { hours: 24 });
25+ return defer({ bay, telemetry });
1426}
1527
1628export default function BayDetail() {
1729 const { bay, telemetry } = useLoaderData<typeof loader>();
1830 return (
1931 <div className="bay-detail">
2032 <BayHeader bay={bay} />
33+ <Suspense fallback={<p className="spark-skeleton">Loading EC/pH trend…</p>}>
34+ <Await resolve={telemetry}>
35+ {(series) => <TelemetrySparkline series={series} />}
36+ </Await>
37+ </Suspense>
21- <TelemetrySparkline series={telemetry} />
2238 </div>
2339 );
2440}