From ef55c49e43595d1504cdf022b22194ddc5a9d21a Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Wed, 17 Jun 2026 01:00:31 +0000 Subject: [PATCH] fix(epc): tolerate absent EPC data + read recommendations via plan_id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For new-approach properties the modelling pipeline currently writes only epc_property + epc_energy_element + plan/recommendation — property_baseline_ performance, epc_property_energy_performance metrics and the property-row headline columns are not yet populated. - layout: guard propertyMeta.detailsEpc?.estimated (detailsEpc can be absent) - resolveConditionReport: degrade to an all-Unknown report instead of throwing when the EPC graph/legacy row is missing (no more 500s) - getProperties: join recommendation via recommendation.plan_id instead of the retired plan_recommendations table, so Plan Cost / recommendation SAP populate Co-Authored-By: Claude Opus 4.8 (1M context) --- .../building-passport/[propertyId]/layout.tsx | 2 +- src/app/portfolio/[slug]/utils.ts | 7 ++++--- src/lib/services/epcSources.ts | 15 ++++----------- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/app/portfolio/[slug]/building-passport/[propertyId]/layout.tsx b/src/app/portfolio/[slug]/building-passport/[propertyId]/layout.tsx index a4c68a42..e60c2f85 100644 --- a/src/app/portfolio/[slug]/building-passport/[propertyId]/layout.tsx +++ b/src/app/portfolio/[slug]/building-passport/[propertyId]/layout.tsx @@ -65,7 +65,7 @@ export default async function DashboardLayout(props: { decentHomes={decentHomes} /> - {propertyMeta.detailsEpc.estimated && } + {propertyMeta.detailsEpc?.estimated && } {children} diff --git a/src/app/portfolio/[slug]/utils.ts b/src/app/portfolio/[slug]/utils.ts index cf4ccfac..6025ebfd 100644 --- a/src/app/portfolio/[slug]/utils.ts +++ b/src/app/portfolio/[slug]/utils.ts @@ -736,10 +736,11 @@ export async function getProperties( AND pl.is_default = true LEFT JOIN funding_package fp ON fp.plan_id = pl.id - LEFT JOIN plan_recommendations pr - ON pr.plan_id = pl.id + -- Recommendations link to their plan via recommendation.plan_id (the + -- plan_recommendations join table is retired). Using plan_id is what makes + -- Plan Cost / recommendation SAP populate for new-approach properties. LEFT JOIN recommendation r - ON r.id = pr.recommendation_id + ON r.plan_id = pl.id AND r.default = true AND r.already_installed = false LEFT JOIN property_details_epc epc diff --git a/src/lib/services/epcSources.ts b/src/lib/services/epcSources.ts index d57a9bae..540f073c 100644 --- a/src/lib/services/epcSources.ts +++ b/src/lib/services/epcSources.ts @@ -342,22 +342,15 @@ export async function resolveConditionReport( }); if (prop && isNewApproach(prop.updatedAt)) { - const resolved = await resolveNewConditionReport(id); - if (!resolved) { - throw new Error( - `No epc_property graph found for new-approach property ${propertyId}`, - ); - } - return resolved; + // Degrade gracefully when the epc_property graph is missing — the screens + // render "Unknown" rather than 500ing. + return (await resolveNewConditionReport(id)) ?? legacyConditionReport({}); } const legacy = await db.query.propertyDetailsEpc.findFirst({ where: eq(propertyDetailsEpc.propertyId, id), }); - if (!legacy) { - throw new Error(`No property_details_epc row for property ${propertyId}`); - } - return legacyConditionReport(legacy as Record); + return legacyConditionReport((legacy ?? {}) as Record); } /** The minimal EPC meta the `/api/property-meta` route embeds as `detailsEpc`. */