From dce8afc9079d76314b4ac1d8df5f35e998161906 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Mon, 20 Oct 2025 16:17:26 +0000 Subject: [PATCH 01/15] basic logic for remote assessment live --- .../[slug]/remote-assessment/page.tsx | 134 +++++++++++++++++- src/middleware.ts | 3 - 2 files changed, 127 insertions(+), 10 deletions(-) diff --git a/src/app/portfolio/[slug]/remote-assessment/page.tsx b/src/app/portfolio/[slug]/remote-assessment/page.tsx index b82ec52..51276c8 100644 --- a/src/app/portfolio/[slug]/remote-assessment/page.tsx +++ b/src/app/portfolio/[slug]/remote-assessment/page.tsx @@ -1,12 +1,132 @@ +"use client"; + +import { useState } from "react"; +import { Input } from "@/app/shadcn_components/ui/input"; +import { Button } from "@/app/shadcn_components/ui/button"; +import { + Select, + SelectTrigger, + SelectContent, + SelectItem, + SelectValue, +} from "@/app/shadcn_components/ui/select"; +import { Card } from "@/app/shadcn_components/ui/card"; +import { Pencil } from "lucide-react"; // ✅ already available from lucide-react + export default function RemoteAssessmentPage() { + const [postcode, setPostcode] = useState(""); + const [isLoading, setIsLoading] = useState(false); + const [addresses, setAddresses] = useState([]); + const [selectedAddress, setSelectedAddress] = useState(null); + const [error, setError] = useState(null); + + async function handleSearch() { + setError(null); + setAddresses([]); + setSelectedAddress(null); + + if (!postcode.trim()) { + setError("Please enter a postcode"); + return; + } + + setIsLoading(true); + await new Promise((r) => setTimeout(r, 800)); // simulate delay + + const fakeResults = [ + "10 Downing Street, London, SW1A 2AA", + "11 Downing Street, London, SW1A 2AA", + "12 Downing Street, London, SW1A 2AA", + ]; + + setAddresses(fakeResults); + setIsLoading(false); + } + + function handleChangeAddress() { + setSelectedAddress(null); + } + return ( -
-

Remote Assessment

-

- Welcome to the Remote Assessment page. Here you can start your remote - assessment process. -

- {/* Additional content and components for remote assessment can be added here */} +
+ +

+ Remote Assessment +

+

+ Search for your property using its postcode to start your assessment. +

+ + {/* Step 1: Postcode input */} + {!selectedAddress && ( + <> +
+ setPostcode(e.target.value.toUpperCase())} + placeholder="Enter postcode (e.g. SW1A 2AA)" + className="text-lg" + /> + +
+ + {error &&

{error}

} + + {/* Step 2: Dropdown of addresses */} + {addresses.length > 0 && ( +
+ + +
+ )} + + )} + + {/* Step 3: Confirmation card */} + {selectedAddress && ( +
+
+

+ Selected Address +

+

{selectedAddress}

+
+ + +
+ )} +
); } diff --git a/src/middleware.ts b/src/middleware.ts index 8727711..f1f44e9 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -6,9 +6,6 @@ export async function middleware(req: NextRequest) { const token = await getToken({ req }); const { pathname } = req.nextUrl; - console.log("token", token); - console.log("onboarded", token?.onboarded); - // If no session, send user to sign-in page if (!token) { return NextResponse.redirect(new URL("/", req.url)); From ca63fa7c99bf922effc425f73073029d2ff565cc Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Mon, 20 Oct 2025 17:01:05 +0000 Subject: [PATCH 02/15] basic wiring for the page --- .../remote-assessment/AddressSearch.tsx | 133 +++++++++++++++++ .../RemoteAssessmentClient.tsx | 56 +++++++ .../remote-assessment/RunAssessment.tsx | 18 +++ .../remote-assessment/ScenarioSetup.tsx | 76 ++++++++++ .../[slug]/remote-assessment/page.tsx | 140 ++---------------- 5 files changed, 298 insertions(+), 125 deletions(-) create mode 100644 src/app/portfolio/[slug]/remote-assessment/AddressSearch.tsx create mode 100644 src/app/portfolio/[slug]/remote-assessment/RemoteAssessmentClient.tsx create mode 100644 src/app/portfolio/[slug]/remote-assessment/RunAssessment.tsx create mode 100644 src/app/portfolio/[slug]/remote-assessment/ScenarioSetup.tsx diff --git a/src/app/portfolio/[slug]/remote-assessment/AddressSearch.tsx b/src/app/portfolio/[slug]/remote-assessment/AddressSearch.tsx new file mode 100644 index 0000000..d434f79 --- /dev/null +++ b/src/app/portfolio/[slug]/remote-assessment/AddressSearch.tsx @@ -0,0 +1,133 @@ +"use client"; + +import { useState } from "react"; +import { Button } from "@/app/shadcn_components/ui/button"; +import { Input } from "@/app/shadcn_components/ui/input"; +import { Card } from "@/app/shadcn_components/ui/card"; +import { Pencil } from "lucide-react"; +import { + Select, + SelectTrigger, + SelectContent, + SelectItem, + SelectValue, +} from "@/app/shadcn_components/ui/select"; + +export default function AddressSearch({ + onAddressSelect, +}: { + onAddressSelect?: (address: string | null) => void; +}) { + const [postcode, setPostcode] = useState(""); + const [addresses, setAddresses] = useState([]); + const [selectedAddress, setSelectedAddress] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [showDropdown, setShowDropdown] = useState(false); + + async function handleSearch() { + setError(null); + setAddresses([]); + if (!postcode.trim()) { + setError("Please enter a postcode"); + return; + } + + setLoading(true); + await new Promise((r) => setTimeout(r, 800)); + + // ✅ Replace with OS Places or postcode.io lookup later + setAddresses([ + "10 Downing Street, London, SW1A 2AA", + "11 Downing Street, London, SW1A 2AA", + "12 Downing Street, London, SW1A 2AA", + ]); + + setLoading(false); + setShowDropdown(true); + } + + function handleSelectAddress(value: string) { + setSelectedAddress(value); + setShowDropdown(false); + if (onAddressSelect) onAddressSelect(value); + } + + function handleChangeAddress() { + setSelectedAddress(null); + setShowDropdown(true); + if (onAddressSelect) onAddressSelect(null); + } + + return ( + +

+ Step 1: Search for Address +

+ + {/* Hide postcode/search once address is selected */} + {!selectedAddress && ( +
+ setPostcode(e.target.value.toUpperCase())} + className="text-lg" + /> + +
+ )} + + {error &&

{error}

} + + {/* Address Dropdown */} + {showDropdown && addresses.length > 0 && ( +
+ + +
+ )} + + {/* Selected Address */} + {selectedAddress && !showDropdown && ( +
+

+ Selected Address +

+

{selectedAddress}

+ +
+ )} +
+ ); +} diff --git a/src/app/portfolio/[slug]/remote-assessment/RemoteAssessmentClient.tsx b/src/app/portfolio/[slug]/remote-assessment/RemoteAssessmentClient.tsx new file mode 100644 index 0000000..dcc81e4 --- /dev/null +++ b/src/app/portfolio/[slug]/remote-assessment/RemoteAssessmentClient.tsx @@ -0,0 +1,56 @@ +"use client"; + +import { useState } from "react"; +import AddressSearch from "./AddressSearch"; +import ScenarioSetup from "./ScenarioSetup"; +import RunAssessment from "./RunAssessment"; + +export default function RemoteAssessmentClient({ + portfolioId, + scenarios, +}: { + portfolioId: string; + scenarios: { + id: string; + name: string; + housingType: string; + goal: string; + goalValue: string | null; + }[]; +}) { + const [selectedAddress, setSelectedAddress] = useState(null); + + return ( +
+

+ Remote Assessment +

+ + + +
+ +
+ +
+ +
+
+ ); +} diff --git a/src/app/portfolio/[slug]/remote-assessment/RunAssessment.tsx b/src/app/portfolio/[slug]/remote-assessment/RunAssessment.tsx new file mode 100644 index 0000000..6a5f584 --- /dev/null +++ b/src/app/portfolio/[slug]/remote-assessment/RunAssessment.tsx @@ -0,0 +1,18 @@ +"use client"; + +import { Card } from "@/app/shadcn_components/ui/card"; +import { Button } from "@/app/shadcn_components/ui/button"; +import { Play } from "lucide-react"; + +export default function RunAssessment() { + return ( + +

+ Step 3: Run Assessment +

+ +
+ ); +} diff --git a/src/app/portfolio/[slug]/remote-assessment/ScenarioSetup.tsx b/src/app/portfolio/[slug]/remote-assessment/ScenarioSetup.tsx new file mode 100644 index 0000000..a12a51c --- /dev/null +++ b/src/app/portfolio/[slug]/remote-assessment/ScenarioSetup.tsx @@ -0,0 +1,76 @@ +"use client"; + +import { useState } from "react"; +import { Card } from "@/app/shadcn_components/ui/card"; +import { Input } from "@/app/shadcn_components/ui/input"; +import { Button } from "@/app/shadcn_components/ui/button"; +import { SelectDropdown } from "@/app/portfolio/[slug]/components/RemoteAssessmentDropdowns"; + +export default function ScenarioSetup({ + portfolioId, + scenarios, + disabled = false, +}: { + portfolioId: string; + scenarios: { + id: string; + name: string; + housingType: string; + goal: string; + goalValue: string | null; + }[]; + disabled?: boolean; +}) { + const [selectedScenario, setSelectedScenario] = useState(null); + + return ( + +

+ Step 2: Select or Create Scenario +

+ + ({ + label: s.name, + value: s.id, + })), + ]} + selectedOption={selectedScenario || ""} + onSelectOption={(opt) => setSelectedScenario(opt.value)} + /> + +
+ + + +
+ + +
+ ); +} diff --git a/src/app/portfolio/[slug]/remote-assessment/page.tsx b/src/app/portfolio/[slug]/remote-assessment/page.tsx index 51276c8..d1b4c62 100644 --- a/src/app/portfolio/[slug]/remote-assessment/page.tsx +++ b/src/app/portfolio/[slug]/remote-assessment/page.tsx @@ -1,132 +1,22 @@ -"use client"; - -import { useState } from "react"; -import { Input } from "@/app/shadcn_components/ui/input"; -import { Button } from "@/app/shadcn_components/ui/button"; +import RemoteAssessmentClient from "./RemoteAssessmentClient"; import { - Select, - SelectTrigger, - SelectContent, - SelectItem, - SelectValue, -} from "@/app/shadcn_components/ui/select"; -import { Card } from "@/app/shadcn_components/ui/card"; -import { Pencil } from "lucide-react"; // ✅ already available from lucide-react + getPortfolio, + getPortfolioScenarios, +} from "@/app/portfolio/[slug]/utils"; -export default function RemoteAssessmentPage() { - const [postcode, setPostcode] = useState(""); - const [isLoading, setIsLoading] = useState(false); - const [addresses, setAddresses] = useState([]); - const [selectedAddress, setSelectedAddress] = useState(null); - const [error, setError] = useState(null); +export default async function RemoteAssessmentPage(props: { + params: Promise<{ slug: string }>; + searchParams: Promise<{ + [key: string]: string | string[] | undefined | number; + }>; +}) { + const params = await props.params; + const portfolioId = params.slug; - async function handleSearch() { - setError(null); - setAddresses([]); - setSelectedAddress(null); - - if (!postcode.trim()) { - setError("Please enter a postcode"); - return; - } - - setIsLoading(true); - await new Promise((r) => setTimeout(r, 800)); // simulate delay - - const fakeResults = [ - "10 Downing Street, London, SW1A 2AA", - "11 Downing Street, London, SW1A 2AA", - "12 Downing Street, London, SW1A 2AA", - ]; - - setAddresses(fakeResults); - setIsLoading(false); - } - - function handleChangeAddress() { - setSelectedAddress(null); - } + // 🔹 Replace this with your real Drizzle query + const scenarios = await getPortfolioScenarios(portfolioId); return ( -
- -

- Remote Assessment -

-

- Search for your property using its postcode to start your assessment. -

- - {/* Step 1: Postcode input */} - {!selectedAddress && ( - <> -
- setPostcode(e.target.value.toUpperCase())} - placeholder="Enter postcode (e.g. SW1A 2AA)" - className="text-lg" - /> - -
- - {error &&

{error}

} - - {/* Step 2: Dropdown of addresses */} - {addresses.length > 0 && ( -
- - -
- )} - - )} - - {/* Step 3: Confirmation card */} - {selectedAddress && ( -
-
-

- Selected Address -

-

{selectedAddress}

-
- - -
- )} -
-
+ ); } From 6df5dc4b23dd8e1876f9f168b905531bdfe743c9 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Mon, 20 Oct 2025 18:14:07 +0000 Subject: [PATCH 03/15] fixed form logic --- .../[slug]/components/FormSchema.tsx | 13 +- .../remote-assessment/ScenarioSetup.tsx | 297 +++++++++++++++--- 2 files changed, 262 insertions(+), 48 deletions(-) diff --git a/src/app/portfolio/[slug]/components/FormSchema.tsx b/src/app/portfolio/[slug]/components/FormSchema.tsx index 1a2c36f..1591f65 100644 --- a/src/app/portfolio/[slug]/components/FormSchema.tsx +++ b/src/app/portfolio/[slug]/components/FormSchema.tsx @@ -50,11 +50,14 @@ export const uploadCsvSchema = baseFormSchema.extend({ if (val === "" || val === undefined) return undefined; return Number(val); }, z.number().min(0.1)), - budget: z.preprocess((val) => { - if (val === "" || val === undefined) return undefined; - if (val === null) return null; - return Number(val); - }, z.union([z.number(), z.null()]).optional()), + budget: z.preprocess( + (val) => { + if (val === "" || val === undefined) return undefined; + if (val === null) return null; + return Number(val); + }, + z.union([z.number(), z.null()]).optional() + ), }); export type UploadCsvFormValues = z.infer; diff --git a/src/app/portfolio/[slug]/remote-assessment/ScenarioSetup.tsx b/src/app/portfolio/[slug]/remote-assessment/ScenarioSetup.tsx index a12a51c..3607453 100644 --- a/src/app/portfolio/[slug]/remote-assessment/ScenarioSetup.tsx +++ b/src/app/portfolio/[slug]/remote-assessment/ScenarioSetup.tsx @@ -1,27 +1,122 @@ "use client"; -import { useState } from "react"; +import { useState, useMemo } from "react"; +import { useForm, FormProvider } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { z } from "zod"; + +import { + FormField, + FormItem, + FormLabel, + FormControl, + FormMessage, +} from "@/app/shadcn_components/ui/form"; + import { Card } from "@/app/shadcn_components/ui/card"; import { Input } from "@/app/shadcn_components/ui/input"; import { Button } from "@/app/shadcn_components/ui/button"; -import { SelectDropdown } from "@/app/portfolio/[slug]/components/RemoteAssessmentDropdowns"; +import { + SelectScenarioDropdown, + SelectDropdown, + ScenarioOption, +} from "@/app/portfolio/[slug]/components/RemoteAssessmentDropdowns"; +import MeasuresCheckboxes from "@/app/portfolio/[slug]/components/MeasuresCheckboxes"; +import { measuresList } from "@/app/db/schema/recommendations"; +import { ScenarioSelect } from "@/app/db/schema/recommendations"; +import { + RemoteAssessmentFormSchema, + type RemoteAssessmentFormValues, +} from "@/app/portfolio/[slug]/components/FormSchema"; +const housingTypeOptions = [ + { label: "Social", value: "Social" }, + { label: "Private", value: "Private" }, +]; + +// ------------------- +// Component +// ------------------- export default function ScenarioSetup({ portfolioId, scenarios, disabled = false, + onSubmitScenario, }: { portfolioId: string; - scenarios: { - id: string; - name: string; - housingType: string; - goal: string; - goalValue: string | null; - }[]; + scenarios: ScenarioSelect[]; disabled?: boolean; + onSubmitScenario?: (values: RemoteAssessmentFormValues) => void; }) { + const NEW_SENTINEL = "__new__"; const [selectedScenario, setSelectedScenario] = useState(null); + const [showMeasures, setShowMeasures] = useState(false); + + const form = useForm({ + resolver: zodResolver(RemoteAssessmentFormSchema), + mode: "onChange", + defaultValues: { + scenario: "", + goal: "", + goalValue: "", + budget: undefined, + housingType: "Social", + addressLineOne: "", + postcode: "", + uprn: 0, + valuation: 0, + propertyType: null, + builtForm: null, + measures: measuresList, + }, + }); + + const { setValue, watch, handleSubmit, formState } = form; + const values = watch(); + + const scenarioOptions: ScenarioOption[] = useMemo( + () => + scenarios.map((s) => ({ + label: s.name || "", + value: String(s.id) || "", + housingType: s.housingType || "", + goal: s.goal || "", + goalValue: s.goalValue || "", + })), + [scenarios] + ); + + function handleSelect(opt: ScenarioOption) { + setSelectedScenario(opt.value); + + if (opt.value === NEW_SENTINEL) { + form.reset({ + ...form.getValues(), + scenario: "", + housingType: "", + goal: "", + goalValue: "", + budget: undefined, + valuation: undefined, + measures: measuresList, // all measures preselected + }); + } else { + form.reset({ + scenario: opt.label || "", + housingType: opt.housingType || "", + goal: opt.goal || "", + goalValue: opt.goalValue || "", + budget: undefined, + valuation: undefined, + measures: measuresList, + }); + } + } + + function onSubmit(data: RemoteAssessmentFormValues) { + if (onSubmitScenario) onSubmitScenario(data); + console.log("Submitted scenario data:", data); + } return ( - ({ - label: s.name, - value: s.id, - })), - ]} - selectedOption={selectedScenario || ""} - onSelectOption={(opt) => setSelectedScenario(opt.value)} - /> + +
+
+ + +
-
- - - -
+ {selectedScenario && ( + <> + {/* Scenario Name + Housing Type */} +
+ ( + + Scenario Name + + + + + + )} + /> - + ( + + Housing Type + + {selectedScenario === NEW_SENTINEL ? ( + field.onChange(opt.value)} + /> + ) : ( + + )} + + + + )} + /> +
+ + {/* Goal + EPC */} +
+ ( + + Goal + + {selectedScenario === NEW_SENTINEL ? ( + field.onChange(opt.value)} + /> + ) : ( + + )} + + + + )} + /> + + {values.goal === "Increasing EPC" && ( + ( + + Target EPC Rating + + {selectedScenario === NEW_SENTINEL ? ( + + field.onChange(opt.value) + } + /> + ) : ( + + )} + + + + )} + /> + )} +
+ + {/* Measures Section */} +
+ + {showMeasures && } +
+ +
+ +
+ + )} +
+
); } From 45c95340c85c045949dc8f7cce265488481b18bd Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Mon, 20 Oct 2025 21:27:52 +0000 Subject: [PATCH 04/15] fixed typescript error --- .../[slug]/remote-assessment/RemoteAssessmentClient.tsx | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/app/portfolio/[slug]/remote-assessment/RemoteAssessmentClient.tsx b/src/app/portfolio/[slug]/remote-assessment/RemoteAssessmentClient.tsx index dcc81e4..3534800 100644 --- a/src/app/portfolio/[slug]/remote-assessment/RemoteAssessmentClient.tsx +++ b/src/app/portfolio/[slug]/remote-assessment/RemoteAssessmentClient.tsx @@ -4,19 +4,14 @@ import { useState } from "react"; import AddressSearch from "./AddressSearch"; import ScenarioSetup from "./ScenarioSetup"; import RunAssessment from "./RunAssessment"; +import { ScenarioSelect } from "@/app/db/schema/recommendations"; export default function RemoteAssessmentClient({ portfolioId, scenarios, }: { portfolioId: string; - scenarios: { - id: string; - name: string; - housingType: string; - goal: string; - goalValue: string | null; - }[]; + scenarios: ScenarioSelect[]; }) { const [selectedAddress, setSelectedAddress] = useState(null); From 54ccbf93dd1b7715ba275e6195b54d96286dc2b4 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Tue, 21 Oct 2025 12:49:36 +0000 Subject: [PATCH 05/15] basic setup for remote assessment live --- src/app/components/portfolio/Toolbar.tsx | 7 - .../[slug]/components/FormSchema.tsx | 6 +- .../components/RemoteAssessmentModal.tsx | 948 ------------------ .../remote-assessment/AddressSearch.tsx | 9 +- .../RemoteAssessmentClient.tsx | 36 +- .../remote-assessment/RunAssessment.tsx | 18 - .../remote-assessment/ScenarioSetup.tsx | 53 +- 7 files changed, 76 insertions(+), 1001 deletions(-) delete mode 100644 src/app/portfolio/[slug]/components/RemoteAssessmentModal.tsx delete mode 100644 src/app/portfolio/[slug]/remote-assessment/RunAssessment.tsx diff --git a/src/app/components/portfolio/Toolbar.tsx b/src/app/components/portfolio/Toolbar.tsx index cc50eb1..d3b8222 100644 --- a/src/app/components/portfolio/Toolbar.tsx +++ b/src/app/components/portfolio/Toolbar.tsx @@ -14,7 +14,6 @@ import { import AddNewDropDown from "./AddNew"; import { cva } from "class-variance-authority"; import UploadCsvModal from "@/app/portfolio/[slug]/components/UploadCsvModal"; -import RemoteAssessmentModal from "@/app/portfolio/[slug]/components/RemoteAssessmentModal"; import { useState } from "react"; import { useRouter } from "next/navigation"; import { ScenarioSelect } from "@/app/db/schema/recommendations"; @@ -103,12 +102,6 @@ export function Toolbar({ portfolioId, scenarios }: ToolbarProps) { setIsRemoteAssessmentOpen={setIsRemoteAssessmentOpen} /> - data.goal !== "Increasing EPC" || !!data.goalValue, { path: ["goalValue"], diff --git a/src/app/portfolio/[slug]/components/RemoteAssessmentModal.tsx b/src/app/portfolio/[slug]/components/RemoteAssessmentModal.tsx deleted file mode 100644 index 0a11c00..0000000 --- a/src/app/portfolio/[slug]/components/RemoteAssessmentModal.tsx +++ /dev/null @@ -1,948 +0,0 @@ -"use client"; - -import { - Dialog, - DialogBackdrop, - DialogPanel, - DialogTitle, - Transition, - TransitionChild, -} from "@headlessui/react"; - -import { Fragment, useMemo } from "react"; -import { Input } from "@/app/shadcn_components/ui/input"; -import { Button } from "@/app/shadcn_components/ui/button"; -import { useMutation } from "@tanstack/react-query"; -import { useSession } from "next-auth/react"; -import { useForm, FormProvider } from "react-hook-form"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { - FormField, - FormItem, - FormLabel, - FormControl, - FormMessage, - FormDescription, -} from "@/app/shadcn_components/ui/form"; -import { useToast } from "@/app/hooks/use-toast"; -import { ScenarioSelect } from "@/app/db/schema/recommendations"; -import { useState } from "react"; -import { - SelectScenarioDropdown, - SelectDropdown, -} from "./RemoteAssessmentDropdowns"; -import MeasuresCheckboxes from "./MeasuresCheckboxes"; -import { measuresList } from "@/app/db/schema/recommendations"; -import { - RemoteAssessmentFormSchema, - RemoteAssessmentFormValues, -} from "./FormSchema"; - -type Option = { - label: string; - value: string; - disabled?: boolean; -}; - -type DropdownProps = { - options: Option[]; - selectedOption: string; - onSelectOption: (option: Option) => void; - width?: string; -}; - -// Extend the existing props -type OptionalDropdownProps = Omit & { - selectedOption: string | null | undefined; -}; - -const selecthousingTypeOptions = [ - { - label: "Social", - value: "Social", - disabled: false, - }, - { - label: "Private", - value: "Private", - disabled: false, - }, -]; - -const propertyTypeOptions = [ - { - label: "House", - value: "House", - disabled: false, - }, - { - label: "Flat", - value: "Flat", - disabled: false, - }, - { - label: "Bungalow", - value: "bungalow", - disabled: false, - }, - { - label: "Maisonette", - value: "Maisonette", - disabled: false, - }, - { - label: "Other", - value: "Other", - disabled: false, - }, -]; - -const builtFormOptions = [ - { - label: "Detached", - value: "Detached", - disabled: false, - }, - { - label: "Semi-Detached", - value: "Semi-Detached", - disabled: false, - }, - { - label: "Mid-Terrace", - value: "Mid-Terrace", - disabled: false, - }, - { - label: "End-Terrace", - value: "End-Terrace", - disabled: false, - }, -]; - -const selectGoalOptions = [ - { - label: "Increasing EPC", - value: "Increasing EPC", - disabled: false, - }, - { - label: "Energy Savings", - value: "Energy Savings", - disabled: false, - }, - { - label: "Reducing CO2 emissions", - value: "Reducing CO2 emissions", - disabled: false, - }, -]; - -const goalValueOptions = [ - { - label: "C", - value: "C", - disabled: false, - }, - { - label: "B", - value: "B", - disabled: false, - }, - { - label: "A", - value: "A", - disabled: false, - }, -]; - -interface EngineTriggerBody { - portfolio_id: string; - housing_type: string; - goal: string; - goal_value: string | null; - trigger_file_path: string; - already_installed_file_path: string; - patches_file_path: string; - non_invasive_recommendations_file_path: string; - valuation_file_path: string; - scenario_name: string; - multi_plan: boolean; - budget: number | null; - event_type: string; - inclusions: (typeof measuresList)[number][]; - scenario_id?: string | null; -} - -async function uploadCsvToS3({ - presignedUrl, - file, -}: { - presignedUrl: string; - file: Blob; -}) { - try { - const response = await fetch(presignedUrl, { - method: "PUT", - body: file, - headers: { "Content-Type": "text/csv" }, - }); - - if (!response.ok) { - console.error(response); - throw new Error("Network response was not ok"); - } - } catch (error) { - console.error(error); - throw new Error("Upload failed."); - } - console.log("File uploaded successfully"); - return { success: true }; -} - -async function generatePresignedUrl({ - userId, - portfolioId, - fileKey, -}: { - userId: string; - portfolioId: string; - fileKey: string; -}) { - // fileKey is a location in S3 where we want to upload the file - const response = await fetch("/api/upload/csv", { - method: "POST", - body: JSON.stringify({ - userId, - portfolioId, - fileKey, - }), - }); - - if (!response.ok) { - throw new Error("Failed to generate presigned url"); - } - - const data = await response.json(); - - data.fileKey = fileKey; - - return data; -} - -function generateS3Keys(userId: string, portfolioId: string) { - const timestamp = new Date().toISOString().replace(/[:.-]/g, ""); - const assetListFileKey = `${userId}/${portfolioId}/${timestamp}/asset_list.csv`; - const valuationDataFileKey = `${userId}/${portfolioId}/${timestamp}/valuation_data.csv`; - return { assetListFileKey, valuationDataFileKey }; -} - -type GenericObject = Record; - -const convertToCSV = >(data: T[]): string => { - if (data.length === 0) return ""; - - const headers = Object.keys(data[0]) as (keyof T)[]; - - const escape = (value: any): string => { - if (value == null) return ""; - - const str = String(value); - - // Check if field contains special characters - if (/[",\n]/.test(str)) { - // Escape double quotes and wrap in quotes - return `"${str.replace(/"/g, '""')}"`; - } - - return str; - }; - - const rows = data.map((row) => - headers.map((header) => escape(row[header])).join(",") - ); - - return [headers.join(","), ...rows].join("\n"); -}; - -function useCreateRemoteAssessment({ - portfolioId, - uprn, - addressLineOne, - postcode, - valuation, - propertyType, - builtForm, - measures, - scenarioId, -}: { - portfolioId: string; - uprn: number | undefined | null; - addressLineOne: string; - postcode: string; - valuation: number | undefined | null; - measures: (typeof measuresList)[number][]; - propertyType?: string | null; - builtForm?: string | null; - scenarioId?: string | null; -}) { - // 1) We want to upload the asset data. To do this, we format the asset data, generate a presigned URL, and upload the data to S3. - // 2) We then want to upload valuation data. To do this, we format the valuation data, generate a presigned URL, and upload the data to S3. - // 3) Trigger the engine!!!! This is an api at /api/plan/trigger with our body that we looked at in Miro - - // Set up the mutation with react-query, to generate a presigned URL - - const session = useSession(); - const userId = String(session.data?.user.dbId); - - if (uprn === undefined || valuation === undefined) { - throw new Error("UPRN and valuation must be provided"); - } - - const { assetListFileKey, valuationDataFileKey } = useMemo( - () => generateS3Keys(userId, portfolioId), - [userId, portfolioId] - ); - - const { - mutate: mutateUploadFile, - isLoading: uploadFileIsLoading, - isError: uploadFileIsError, - } = useMutation(uploadCsvToS3, { - onSuccess: (data) => { - // Callback for successful mutation - console.log("Files uploaded successfully"); - // Trigger the engine here if needed - }, - onError: (error) => { - // Callback for failed mutation - console.error("Error uploading files:", error); - }, - }); - - const { - mutate: mutatePresignedUrl, - isLoading: presignedUrlIsLoading, - isError: presignedUrlIsError, - } = useMutation(generatePresignedUrl, { - onSuccess: (data) => { - // console.log(data.url); - // // On success, upload to that URL!!!! - - let csvFile: Blob = new Blob(); - - if (data.fileKey === assetListFileKey) { - const assetList = [ - { - uprn: uprn, - address: addressLineOne, - postcode: postcode, - property_type: propertyType, - built_form: builtForm, - }, - ]; - - csvFile = new Blob([convertToCSV(assetList)], { - type: "text/csv", - }); - } else if (data.fileKey === valuationDataFileKey) { - const valuationData = [ - { - uprn: uprn, - valuation: valuation, - }, - ]; - - csvFile = new Blob([convertToCSV(valuationData)], { - type: "text/csv", - }); - } - - mutateUploadFile({ - file: csvFile, - presignedUrl: data.url, - }); - }, - onError: (error) => { - console.error(error); - }, - }); - - async function triggerEngine(data: RemoteAssessmentFormValues) { - try { - // Goal value should not be missing at this point - if (data.goal === "Increasing EPC" && !data.goalValue) { - throw new Error("Goal value is required"); - } - - const triggerBody: EngineTriggerBody = { - scenario_id: scenarioId === "__new__" ? null : scenarioId, - portfolio_id: portfolioId, - housing_type: data.housingType, - goal: data.goal, - // We only send goal_value if the goal is "Increasing EPC" - goal_value: data.goalValue || null, - trigger_file_path: assetListFileKey, - already_installed_file_path: "", - patches_file_path: "", - non_invasive_recommendations_file_path: "", - valuation_file_path: valuationDataFileKey, - scenario_name: data.scenario, - inclusions: data.measures, - multi_plan: true, - // If the goal is "Increasing EPC", we don't send a budget - budget: data.budget || null, - event_type: "remote_assessment", - }; - - console.log("Triggering engine with body:", triggerBody); - - const response = await fetch("/api/plan/trigger", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(triggerBody), - }); - - if (!response.ok) { - throw new Error("Failed to trigger engine"); - } - } catch (error) { - console.error("Error triggering engine:", error); - throw error; - } - } - - async function handleSubmit(formData: RemoteAssessmentFormValues) { - try { - await Promise.all([ - mutatePresignedUrl({ - userId, - portfolioId, - fileKey: assetListFileKey, - }), - mutatePresignedUrl({ - userId, - portfolioId, - fileKey: valuationDataFileKey, - }), - ]); - - await triggerEngine(formData); - } catch (error) { - console.error("Error in submission process:", error); - } - } - - return { - handleSubmit, - triggerEngine, - mutateUploadFile, - presignedUrlIsLoading, - presignedUrlIsError, - uploadFileIsLoading, - uploadFileIsError, - }; -} - -export default function RemoteAssessmentModal({ - isOpen, - setIsOpen, - portfolioId, - scenarios, -}: { - isOpen: boolean; - setIsOpen: (open: boolean) => void; - portfolioId: string; - scenarios: ScenarioSelect[]; -}) { - const NEW_SENTINEL = "__new__"; - const [selectedScenario, setSelectedScenario] = useState(null); - const { toast } = useToast(); - const [showMeasures, setShowMeasures] = useState(false); - - const scenarioOptions: Option[] = useMemo( - () => [ - ...scenarios.map((s) => ({ - label: s.name || "", - value: String(s.id) || "", - disabled: false, - })), - ], - [scenarios] - ); - - const form = useForm({ - resolver: zodResolver(RemoteAssessmentFormSchema), - mode: "onChange", - defaultValues: { - scenario: "", - housingType: "", - goal: "", - goalValue: "", - budget: undefined, - addressLineOne: "", - postcode: "", - uprn: undefined, - valuation: undefined, - propertyType: null, - builtForm: null, - measures: measuresList, - }, - }); - const { reset, setValue, formState } = form; - const { isValid, isSubmitting } = formState; - - const measures = form.watch("measures"); - const goal = form.watch("goal"); - - const { - handleSubmit: triggerAssessment, - presignedUrlIsLoading, - presignedUrlIsError, - } = useCreateRemoteAssessment({ - portfolioId, - uprn: form.watch("uprn") ?? null, - addressLineOne: form.watch("addressLineOne"), - postcode: form.watch("postcode"), - valuation: form.watch("valuation") ?? null, - propertyType: form.watch("propertyType"), - builtForm: form.watch("builtForm"), - measures: measures, - scenarioId: selectedScenario, - }); - - const onSelectScenario = (opt: Option) => { - setSelectedScenario(opt.value); - if (opt.value === NEW_SENTINEL) { - reset({ - ...form.getValues(), - scenario: "", - housingType: "", - goal: "", - goalValue: "", - }); - } else { - const picked = scenarios.find((s) => String(s.id) === opt.value); - - if (!picked) return; - setValue("scenario", picked.name || ""); - setValue("housingType", picked.housingType); - setValue("goal", picked.goal); - setValue("goalValue", picked.goalValue || ""); - } - }; - - const onSubmit = form.handleSubmit(async (data) => { - await triggerAssessment(data); - form.reset(); - setIsOpen(false); - toast({ title: "Remote assessment sent" }); - }); - - return ( - - setIsOpen(false)} - > -
- - - - - {/* Spacer for centering */} - - - - - - Remote Assessment Details - - - -
- {/* Scenario selector */} - - Select scenario - - - - - - {selectedScenario !== null && ( - <> -
- {/* Scenario Name */} - ( - - - Scenario Name - - - - - - - )} - /> - - {/* Housing Type */} - ( - - - Housing Type - - - {selectedScenario === NEW_SENTINEL ? ( - - field.onChange(o.value) - } - /> - ) : ( - - )} - - - - )} - /> -
- -
- {/* Goal */} - ( - - - Goal - - - {selectedScenario === NEW_SENTINEL ? ( - - field.onChange(o.value) - } - /> - ) : ( - - )} - - - - )} - /> - - {goal && ( - <> - {goal === "Increasing EPC" && ( - ( - - - Target EPC Rating - - - {selectedScenario === NEW_SENTINEL ? ( - - field.onChange(opt.value) - } - /> - ) : ( - - )} - - - - )} - /> - )} - - {/* ✅ Budget shows for all goals but is only mandatory when goal != Increasing EPC */} - ( - - - {/* We mark budget as (optional) when the goal is increasing EPC*/} - Budget (£){" "} - {goal === "Increasing EPC" && ( - - (optional) - - )} - - - - field.onChange( - e.target.value === "" - ? undefined - : Number(e.target.value) - ) - } - className="border-brandbrown focus-visible:ring-brandbrown focus-visible:border-brandbrown" - /> - - - - )} - /> - - )} -
- - )} - - ( - - Address - - - - - - )} - /> - - ( - - - Postcode - - - - - - - )} - /> - - ( - - UPRN - - - field.onChange( - e.target.value === "" - ? undefined - : Number(e.target.value) - ) - } - className="border-brandbrown focus-visible:ring-brandbrown focus-visible:border-brandbrown" - /> - - - - )} - /> - - ( - - - Valuation - - - The valuation can be found at{" "} - - zoopla property page - - - - - field.onChange( - e.target.value === "" - ? undefined - : Number(e.target.value) - ) - } - className="border-brandbrown focus-visible:ring-brandbrown focus-visible:border-brandbrown" - /> - - - - )} - /> - -
-

- Optional: Property Type and Built Form - are only required if no EPC is available. -

-
- ( - - Property Type - - field.onChange(o.value)} - /> - - - - )} - /> - ( - - Built Form - - field.onChange(o.value)} - /> - - - - )} - /> -
-
- - {/* Measures Section */} -
- - {showMeasures && } -
- -
- - -
- - {presignedUrlIsError && ( -

Error uploading files

- )} - -
-
-
-
-
-
- ); -} -function setIsOpen(arg0: boolean) { - throw new Error("Function not implemented."); -} diff --git a/src/app/portfolio/[slug]/remote-assessment/AddressSearch.tsx b/src/app/portfolio/[slug]/remote-assessment/AddressSearch.tsx index d434f79..ab0f092 100644 --- a/src/app/portfolio/[slug]/remote-assessment/AddressSearch.tsx +++ b/src/app/portfolio/[slug]/remote-assessment/AddressSearch.tsx @@ -15,10 +15,13 @@ import { export default function AddressSearch({ onAddressSelect, + onPostcodeSelect, + postcode, }: { - onAddressSelect?: (address: string | null) => void; + onAddressSelect: (address: string | null) => void; + onPostcodeSelect: (postcode: string) => void; + postcode: string; }) { - const [postcode, setPostcode] = useState(""); const [addresses, setAddresses] = useState([]); const [selectedAddress, setSelectedAddress] = useState(null); const [loading, setLoading] = useState(false); @@ -71,7 +74,7 @@ export default function AddressSearch({ setPostcode(e.target.value.toUpperCase())} + onChange={(e) => onPostcodeSelect(e.target.value.toUpperCase())} className="text-lg" />
); } diff --git a/src/app/portfolio/[slug]/remote-assessment/RunAssessment.tsx b/src/app/portfolio/[slug]/remote-assessment/RunAssessment.tsx deleted file mode 100644 index 6a5f584..0000000 --- a/src/app/portfolio/[slug]/remote-assessment/RunAssessment.tsx +++ /dev/null @@ -1,18 +0,0 @@ -"use client"; - -import { Card } from "@/app/shadcn_components/ui/card"; -import { Button } from "@/app/shadcn_components/ui/button"; -import { Play } from "lucide-react"; - -export default function RunAssessment() { - return ( - -

- Step 3: Run Assessment -

- -
- ); -} diff --git a/src/app/portfolio/[slug]/remote-assessment/ScenarioSetup.tsx b/src/app/portfolio/[slug]/remote-assessment/ScenarioSetup.tsx index 3607453..2c208d1 100644 --- a/src/app/portfolio/[slug]/remote-assessment/ScenarioSetup.tsx +++ b/src/app/portfolio/[slug]/remote-assessment/ScenarioSetup.tsx @@ -3,7 +3,7 @@ import { useState, useMemo } from "react"; import { useForm, FormProvider } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; -import { z } from "zod"; +import { Play } from "lucide-react"; import { FormField, @@ -41,12 +41,18 @@ export default function ScenarioSetup({ portfolioId, scenarios, disabled = false, - onSubmitScenario, + selectedAddress, + selectedPostcode, + isSubmitting, + onSubmitRemoteAssessment, }: { portfolioId: string; scenarios: ScenarioSelect[]; disabled?: boolean; - onSubmitScenario?: (values: RemoteAssessmentFormValues) => void; + selectedAddress: string | null; + selectedPostcode: string; + isSubmitting: boolean; + onSubmitRemoteAssessment: (values: RemoteAssessmentFormValues) => void; }) { const NEW_SENTINEL = "__new__"; const [selectedScenario, setSelectedScenario] = useState(null); @@ -63,10 +69,7 @@ export default function ScenarioSetup({ housingType: "Social", addressLineOne: "", postcode: "", - uprn: 0, - valuation: 0, - propertyType: null, - builtForm: null, + uprn: 1, measures: measuresList, }, }); @@ -97,8 +100,10 @@ export default function ScenarioSetup({ goal: "", goalValue: "", budget: undefined, - valuation: undefined, - measures: measuresList, // all measures preselected + measures: measuresList, + addressLineOne: selectedAddress || "", + postcode: selectedPostcode || "", + uprn: 1, // TODO: Replace with real UPRN }); } else { form.reset({ @@ -107,14 +112,17 @@ export default function ScenarioSetup({ goal: opt.goal || "", goalValue: opt.goalValue || "", budget: undefined, - valuation: undefined, measures: measuresList, + addressLineOne: selectedAddress || "", + postcode: selectedPostcode || "", + uprn: 1, }); } } function onSubmit(data: RemoteAssessmentFormValues) { - if (onSubmitScenario) onSubmitScenario(data); + console.log("form Data", data); + onSubmitRemoteAssessment(data); console.log("Submitted scenario data:", data); } @@ -268,14 +276,25 @@ export default function ScenarioSetup({ {showMeasures && } - -
+
From f134bf26b40e592c5cc5394ce6f29840d9bd20cb Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Tue, 21 Oct 2025 18:01:50 +0000 Subject: [PATCH 06/15] added postcode valiation --- src/app/api/postcode/LookupPostcode.ts | 59 +++++ src/app/api/postcode/[postcode]/route.ts | 31 +++ .../remote-assessment/AddressSearch.tsx | 72 +++--- .../useCreateRemoteAssessment.tsx | 230 ++++++++++++++++++ .../remote-assessment/usePostcodeLookup.ts | 72 ++++++ 5 files changed, 435 insertions(+), 29 deletions(-) create mode 100644 src/app/api/postcode/LookupPostcode.ts create mode 100644 src/app/api/postcode/[postcode]/route.ts create mode 100644 src/app/portfolio/[slug]/remote-assessment/useCreateRemoteAssessment.tsx create mode 100644 src/app/portfolio/[slug]/remote-assessment/usePostcodeLookup.ts diff --git a/src/app/api/postcode/LookupPostcode.ts b/src/app/api/postcode/LookupPostcode.ts new file mode 100644 index 0000000..c9376f4 --- /dev/null +++ b/src/app/api/postcode/LookupPostcode.ts @@ -0,0 +1,59 @@ +// src/app/utils/postcodes.ts + +export interface PostcodeLookupResult { + status: number; + result?: { + postcode: string; + country: string; + region: string | null; + admin_district: string | null; + latitude: number; + longitude: number; + }; + error?: string; +} + +/** + * Look up a postcode using postcodes.io. + * Includes automatic retry logic for transient 5xx errors. + */ +export async function lookupPostcode( + postcode: string, + retries = 2 +): Promise { + const url = `https://api.postcodes.io/postcodes/${encodeURIComponent( + postcode.trim() + )}`; + + for (let attempt = 0; attempt <= retries; attempt++) { + try { + const res = await fetch(url); + + if (!res.ok) { + const data = await res.json(); + // Retry only on transient 5xx errors + if (res.status >= 500 && attempt < retries) { + console.warn(`Retrying postcode lookup (attempt ${attempt + 1})`); + await new Promise((r) => setTimeout(r, 500 * (attempt + 1))); + continue; + } + return data; + } + + return await res.json(); + } catch (error) { + if (attempt < retries) { + console.warn(`Network error on attempt ${attempt + 1}, retrying...`); + await new Promise((r) => setTimeout(r, 500 * (attempt + 1))); + } else { + return { + status: 500, + error: "Network error while contacting postcodes.io", + }; + } + } + } + + // Should never reach here + return { status: 500, error: "Unexpected error" }; +} diff --git a/src/app/api/postcode/[postcode]/route.ts b/src/app/api/postcode/[postcode]/route.ts new file mode 100644 index 0000000..203eaee --- /dev/null +++ b/src/app/api/postcode/[postcode]/route.ts @@ -0,0 +1,31 @@ +import { NextResponse } from "next/server"; +import { lookupPostcode } from "../LookupPostcode"; + +export async function GET( + req: Request, + { params }: { params: { postcode: string } } +) { + const { postcode } = await params; + + if (!postcode || typeof postcode !== "string") { + return NextResponse.json( + { error: "Missing or invalid postcode" }, + { status: 400 } + ); + } + + const data = await lookupPostcode(postcode); + + if (data.status === 404) { + return NextResponse.json({ error: "Invalid postcode" }, { status: 404 }); + } + + if (data.status !== 200 || !data.result) { + return NextResponse.json( + { error: data.error || "Postcode lookup failed" }, + { status: data.status || 500 } + ); + } + + return NextResponse.json({ result: data.result }); +} diff --git a/src/app/portfolio/[slug]/remote-assessment/AddressSearch.tsx b/src/app/portfolio/[slug]/remote-assessment/AddressSearch.tsx index ab0f092..c7ec3b2 100644 --- a/src/app/portfolio/[slug]/remote-assessment/AddressSearch.tsx +++ b/src/app/portfolio/[slug]/remote-assessment/AddressSearch.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState } from "react"; +import { useState, useEffect } from "react"; import { Button } from "@/app/shadcn_components/ui/button"; import { Input } from "@/app/shadcn_components/ui/input"; import { Card } from "@/app/shadcn_components/ui/card"; @@ -12,6 +12,7 @@ import { SelectItem, SelectValue, } from "@/app/shadcn_components/ui/select"; +import usePostcodeLookup from "./usePostcodeLookup"; export default function AddressSearch({ onAddressSelect, @@ -24,51 +25,54 @@ export default function AddressSearch({ }) { const [addresses, setAddresses] = useState([]); const [selectedAddress, setSelectedAddress] = useState(null); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); const [showDropdown, setShowDropdown] = useState(false); + const [triggerSearch, setTriggerSearch] = useState(false); + + const { data, isFetching, refetch } = usePostcodeLookup( + postcode, + triggerSearch + ); + + // When postcode data returns successfully (status 200), populate mock addresses + useEffect(() => { + if (data && data.status === 200 && data.result) { + setAddresses([ + `10 Downing Street, London, ${data.result.postcode}`, + `11 Downing Street, London, ${data.result.postcode}`, + `12 Downing Street, London, ${data.result.postcode}`, + ]); + setShowDropdown(true); + } + }, [data]); async function handleSearch() { - setError(null); - setAddresses([]); - if (!postcode.trim()) { - setError("Please enter a postcode"); - return; - } - - setLoading(true); - await new Promise((r) => setTimeout(r, 800)); - - // ✅ Replace with OS Places or postcode.io lookup later - setAddresses([ - "10 Downing Street, London, SW1A 2AA", - "11 Downing Street, London, SW1A 2AA", - "12 Downing Street, London, SW1A 2AA", - ]); - - setLoading(false); - setShowDropdown(true); + if (!postcode.trim()) return; + setTriggerSearch(true); + await refetch(); + setTriggerSearch(false); // Reset trigger after refetch } function handleSelectAddress(value: string) { setSelectedAddress(value); setShowDropdown(false); - if (onAddressSelect) onAddressSelect(value); + onAddressSelect(value); } function handleChangeAddress() { setSelectedAddress(null); setShowDropdown(true); - if (onAddressSelect) onAddressSelect(null); + onAddressSelect(null); } + const showInvalid = data && data.status === 404; + const showServerError = data && data.status === 500; + return (

Step 1: Search for Address

- {/* Hide postcode/search once address is selected */} {!selectedAddress && (
)} - {error &&

{error}

} + {/* Validation + Error feedback */} + {showInvalid && ( +

+ Invalid postcode — please check and try again. +

+ )} + {showServerError && ( +

+ The postcode service is currently unavailable. Please try again later. +

+ )} {/* Address Dropdown */} {showDropdown && addresses.length > 0 && ( @@ -113,7 +127,7 @@ export default function AddressSearch({
)} - {/* Selected Address */} + {/* Selected Address Display */} {selectedAddress && !showDropdown && (

diff --git a/src/app/portfolio/[slug]/remote-assessment/useCreateRemoteAssessment.tsx b/src/app/portfolio/[slug]/remote-assessment/useCreateRemoteAssessment.tsx new file mode 100644 index 0000000..020fb4f --- /dev/null +++ b/src/app/portfolio/[slug]/remote-assessment/useCreateRemoteAssessment.tsx @@ -0,0 +1,230 @@ +"use client"; + +import { useMemo } from "react"; +import { useMutation } from "@tanstack/react-query"; +import { useSession } from "next-auth/react"; +import { measuresList } from "@/app/db/schema/recommendations"; +import { RemoteAssessmentFormValues } from "@/app/portfolio/[slug]/components/FormSchema"; + +interface EngineTriggerBody { + portfolio_id: string; + housing_type: string; + goal: string; + goal_value: string | null; + trigger_file_path: string; + already_installed_file_path: string; + patches_file_path: string; + non_invasive_recommendations_file_path: string; + valuation_file_path: string; + scenario_name: string; + multi_plan: boolean; + budget: number | null; + event_type: string; + inclusions: (typeof measuresList)[number][]; + scenario_id?: string | null; +} + +/* ---------- Helpers ---------- */ + +async function uploadCsvToS3({ + presignedUrl, + file, +}: { + presignedUrl: string; + file: Blob; +}) { + const response = await fetch(presignedUrl, { + method: "PUT", + body: file, + headers: { "Content-Type": "text/csv" }, + }); + + if (!response.ok) { + console.error(response); + throw new Error("Failed to upload CSV to S3"); + } + + console.log("✅ File uploaded successfully:", presignedUrl); + return { success: true }; +} + +async function generatePresignedUrl({ + userId, + portfolioId, + fileKey, +}: { + userId: string; + portfolioId: string; + fileKey: string; +}) { + const response = await fetch("/api/upload/csv", { + method: "POST", + body: JSON.stringify({ userId, portfolioId, fileKey }), + }); + + if (!response.ok) { + throw new Error("Failed to generate presigned URL"); + } + + const data = await response.json(); + return { ...data, fileKey }; +} + +function generateS3Keys(userId: string, portfolioId: string) { + const timestamp = new Date().toISOString().replace(/[:.-]/g, ""); + return { + assetListFileKey: `${userId}/${portfolioId}/${timestamp}/asset_list.csv`, + valuationDataFileKey: `${userId}/${portfolioId}/${timestamp}/valuation_data.csv`, + }; +} + +const convertToCSV = >(data: T[]): string => { + if (data.length === 0) return ""; + const headers = Object.keys(data[0]) as (keyof T)[]; + const escape = (val: any) => + val == null + ? "" + : /[",\n]/.test(String(val)) + ? `"${String(val).replace(/"/g, '""')}"` + : String(val); + return [ + headers.join(","), + ...data.map((r) => headers.map((h) => escape(r[h])).join(",")), + ].join("\n"); +}; + +/* ---------- Main Hook ---------- */ + +function useCreateRemoteAssessment({ + portfolioId, + uprn, + addressLineOne, + postcode, + valuation, + propertyType, + builtForm, + measures, + scenarioId, +}: { + portfolioId: string; + uprn: number | undefined | null; + addressLineOne: string; + postcode: string; + valuation: number | undefined | null; + measures: (typeof measuresList)[number][]; + propertyType?: string | null; + builtForm?: string | null; + scenarioId?: string | null; +}) { + const { data: session } = useSession(); + const userId = String(session?.user.dbId); + + if (uprn === undefined || valuation === undefined) { + console.warn("Missing UPRN or valuation, cannot proceed"); + } + + const { assetListFileKey, valuationDataFileKey } = useMemo( + () => generateS3Keys(userId, portfolioId), + [userId, portfolioId] + ); + + const uploadMutation = useMutation({ + mutationFn: uploadCsvToS3, + }); + + const presignedMutation = useMutation({ + mutationFn: generatePresignedUrl, + onSuccess: (data) => { + let csvFile: Blob; + if (data.fileKey === assetListFileKey) { + const assetList: { + uprn: number | null | undefined; + address: string; + postcode: string; + property_type?: string; + built_form?: string; + }[] = [ + { + uprn, + address: addressLineOne, + postcode, + }, + ]; + + // if we have property type and built form, include them. Handle typescript optionality + if (propertyType) { + assetList[0]["property_type"] = propertyType; + } + if (builtForm) { + assetList[0]["built_form"] = builtForm; + } + + csvFile = new Blob([convertToCSV(assetList)], { type: "text/csv" }); + } else { + const valuationData = [{ uprn, valuation }]; + csvFile = new Blob([convertToCSV(valuationData)], { type: "text/csv" }); + } + + uploadMutation.mutate({ file: csvFile, presignedUrl: data.url }); + }, + }); + + async function triggerEngine(data: RemoteAssessmentFormValues) { + const triggerBody: EngineTriggerBody = { + scenario_id: scenarioId === "__new__" ? null : scenarioId, + portfolio_id: portfolioId, + housing_type: data.housingType, + goal: data.goal, + goal_value: data.goalValue || null, + trigger_file_path: assetListFileKey, + already_installed_file_path: "", + patches_file_path: "", + non_invasive_recommendations_file_path: "", + valuation_file_path: valuation ? valuationDataFileKey : "", // We only pass a valution filepath if we have a valuation + scenario_name: data.scenario, + inclusions: data.measures, + multi_plan: true, + budget: data.budget || null, + event_type: "remote_assessment", + }; + + console.log("🚀 Triggering engine with body:", triggerBody); + + const response = await fetch("/api/plan/trigger", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(triggerBody), + }); + + if (!response.ok) throw new Error("Failed to trigger engine"); + console.log("✅ Engine triggered successfully"); + } + + async function handleSubmit(formData: RemoteAssessmentFormValues) { + console.log("Submitting Remote Assessment form:", formData); + + await Promise.all([ + presignedMutation.mutateAsync({ + userId, + portfolioId, + fileKey: assetListFileKey, + }), + presignedMutation.mutateAsync({ + userId, + portfolioId, + fileKey: valuationDataFileKey, + }), + ]); + + await triggerEngine(formData); + } + + return { + handleSubmit, + triggerEngine, + isUploading: uploadMutation.isLoading || presignedMutation.isLoading, + hasError: uploadMutation.isError || presignedMutation.isError, + }; +} + +export default useCreateRemoteAssessment; diff --git a/src/app/portfolio/[slug]/remote-assessment/usePostcodeLookup.ts b/src/app/portfolio/[slug]/remote-assessment/usePostcodeLookup.ts new file mode 100644 index 0000000..a8c3eed --- /dev/null +++ b/src/app/portfolio/[slug]/remote-assessment/usePostcodeLookup.ts @@ -0,0 +1,72 @@ +"use client"; + +import { useQuery } from "@tanstack/react-query"; + +export interface PostcodeResult { + postcode: string; + country: string; + region: string | null; + admin_district: string | null; + latitude: number; + longitude: number; +} + +export interface PostcodeLookupResponse { + status: number; + result: PostcodeResult | null; + message?: string; +} + +/** + * Calls your /api/postcode/:postcode endpoint. + * Handles 404 gracefully (invalid postcode), + * 500 gracefully (external service issue), + * and only throws on client-side misuse (400). + */ +async function fetchPostcode( + postcode: string +): Promise { + const res = await fetch(`/api/postcode/${encodeURIComponent(postcode)}`); + const data = await res.json(); + + switch (res.status) { + case 200: + return { status: 200, result: data.result }; + case 404: + // Invalid postcode (user input issue) + return { status: 404, result: null, message: "Invalid postcode" }; + case 500: + // External API error + return { + status: 500, + result: null, + message: + "We're having trouble reaching the postcode service. Please try again later.", + }; + case 400: + // Bad query from our side (should not happen in production) + throw new Error("Postcode API query malformed (400)."); + default: + // Unexpected case + return { + status: res.status, + result: null, + message: data.error || "Unexpected response from postcode API", + }; + } +} + +/** + * React Query hook for postcode validation and lookup + */ +function usePostcodeLookup(postcode: string, shouldFetch: boolean) { + return useQuery({ + queryKey: ["postcode-lookup", postcode], + queryFn: () => fetchPostcode(postcode), + enabled: shouldFetch && !!postcode, + retry: false, + staleTime: 1000 * 60 * 5, + }); +} + +export default usePostcodeLookup; From 85390dcabb42bd025be8924895a1eaed4bcd5f14 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Tue, 21 Oct 2025 20:43:51 +0000 Subject: [PATCH 07/15] Added new table to monitor postcode queries --- src/app/db/migrations/meta/_journal.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/app/db/migrations/meta/_journal.json b/src/app/db/migrations/meta/_journal.json index 1b6c514..fda2a5f 100644 --- a/src/app/db/migrations/meta/_journal.json +++ b/src/app/db/migrations/meta/_journal.json @@ -841,6 +841,13 @@ "when": 1760711090309, "tag": "0119_marvelous_blur", "breakpoints": true + }, + { + "idx": 120, + "version": "7", + "when": 1761078881645, + "tag": "0120_watery_captain_america", + "breakpoints": true } ] } \ No newline at end of file From a26cdb3d14b9f3040c6bddeed86f8bc16894b50e Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Thu, 23 Oct 2025 10:47:25 +0000 Subject: [PATCH 08/15] working on os api --- .../remote-assessment/AddressSearch.tsx | 73 +++++++++++++------ 1 file changed, 50 insertions(+), 23 deletions(-) diff --git a/src/app/portfolio/[slug]/remote-assessment/AddressSearch.tsx b/src/app/portfolio/[slug]/remote-assessment/AddressSearch.tsx index c7ec3b2..9c5bc7c 100644 --- a/src/app/portfolio/[slug]/remote-assessment/AddressSearch.tsx +++ b/src/app/portfolio/[slug]/remote-assessment/AddressSearch.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState, useEffect } from "react"; +import { useState } from "react"; import { Button } from "@/app/shadcn_components/ui/button"; import { Input } from "@/app/shadcn_components/ui/input"; import { Card } from "@/app/shadcn_components/ui/card"; @@ -14,6 +14,11 @@ import { } from "@/app/shadcn_components/ui/select"; import usePostcodeLookup from "./usePostcodeLookup"; +interface AddressItem { + uprn: string; + address: string; +} + export default function AddressSearch({ onAddressSelect, onPostcodeSelect, @@ -23,33 +28,50 @@ export default function AddressSearch({ onPostcodeSelect: (postcode: string) => void; postcode: string; }) { - const [addresses, setAddresses] = useState([]); + const [addresses, setAddresses] = useState([]); const [selectedAddress, setSelectedAddress] = useState(null); const [showDropdown, setShowDropdown] = useState(false); const [triggerSearch, setTriggerSearch] = useState(false); + const [loadingAddresses, setLoadingAddresses] = useState(false); + const [addressError, setAddressError] = useState(null); const { data, isFetching, refetch } = usePostcodeLookup( postcode, triggerSearch ); - // When postcode data returns successfully (status 200), populate mock addresses - useEffect(() => { - if (data && data.status === 200 && data.result) { - setAddresses([ - `10 Downing Street, London, ${data.result.postcode}`, - `11 Downing Street, London, ${data.result.postcode}`, - `12 Downing Street, London, ${data.result.postcode}`, - ]); - setShowDropdown(true); - } - }, [data]); - async function handleSearch() { if (!postcode.trim()) return; setTriggerSearch(true); - await refetch(); - setTriggerSearch(false); // Reset trigger after refetch + const validation = await refetch(); + setTriggerSearch(false); + + // Only continue if postcode is valid + if (!validation.data || validation.data.status !== 200) return; + + // Fetch addresses from backend + setLoadingAddresses(true); + setAddressError(null); + try { + const res = await fetch( + `/api/postcode/${encodeURIComponent(postcode)}/addresses` + ); + const json = await res.json(); + + if (!res.ok) { + setAddressError(json.error || "Unable to retrieve addresses"); + setShowDropdown(false); + } else if (json.results?.length) { + setAddresses(json.results); + setShowDropdown(true); + } else { + setAddressError("No addresses found for this postcode"); + } + } catch (err: any) { + setAddressError("There was an issue contacting the address service."); + } finally { + setLoadingAddresses(false); + } } function handleSelectAddress(value: string) { @@ -67,6 +89,8 @@ export default function AddressSearch({ const showInvalid = data && data.status === 404; const showServerError = data && data.status === 500; + const isLoading = isFetching || loadingAddresses; + return (

@@ -83,15 +107,15 @@ export default function AddressSearch({ />

)} - {/* Validation + Error feedback */} + {/* Validation or server errors */} {showInvalid && (

Invalid postcode — please check and try again. @@ -102,8 +126,11 @@ export default function AddressSearch({ The postcode service is currently unavailable. Please try again later.

)} + {addressError && ( +

{addressError}

+ )} - {/* Address Dropdown */} + {/* Address dropdown */} {showDropdown && addresses.length > 0 && (
)} - {/* Selected Address Display */} + {/* Selected address display */} {selectedAddress && !showDropdown && (

From f481103b5e724fdb72b6a1907689507e86e2e037 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Thu, 23 Oct 2025 11:49:04 +0100 Subject: [PATCH 09/15] missing files --- src/app/api/postcode/FormatOsResults.ts | 18 + src/app/api/postcode/LookupOsPlaces.ts | 148 + src/app/api/postcode/OsPlacesToFlat.ts | 28 + .../postcode/[postcode]/addresses/route.ts | 83 + .../0120_watery_captain_america.sql | 7 + src/app/db/migrations/meta/0120_snapshot.json | 3881 +++++++++++++++++ src/app/db/schema/addresses.ts | 35 + 7 files changed, 4200 insertions(+) create mode 100644 src/app/api/postcode/FormatOsResults.ts create mode 100644 src/app/api/postcode/LookupOsPlaces.ts create mode 100644 src/app/api/postcode/OsPlacesToFlat.ts create mode 100644 src/app/api/postcode/[postcode]/addresses/route.ts create mode 100644 src/app/db/migrations/0120_watery_captain_america.sql create mode 100644 src/app/db/migrations/meta/0120_snapshot.json create mode 100644 src/app/db/schema/addresses.ts diff --git a/src/app/api/postcode/FormatOsResults.ts b/src/app/api/postcode/FormatOsResults.ts new file mode 100644 index 0000000..dc68c8e --- /dev/null +++ b/src/app/api/postcode/FormatOsResults.ts @@ -0,0 +1,18 @@ +/** + * Extracts simplified address list from OS Places response. + */ +export function formatOsResults(apiResponse: any) { + if (!apiResponse?.results) return []; + + return apiResponse.results + .map((entry: any) => { + const dpa = entry.DPA; + if (!dpa) return null; + + return { + uprn: dpa.UPRN, + address: dpa.ADDRESS, + }; + }) + .filter(Boolean); +} diff --git a/src/app/api/postcode/LookupOsPlaces.ts b/src/app/api/postcode/LookupOsPlaces.ts new file mode 100644 index 0000000..1bdf590 --- /dev/null +++ b/src/app/api/postcode/LookupOsPlaces.ts @@ -0,0 +1,148 @@ +import { OSPlacesHeader, OSPlacesResponse } from "@/app/db/schema/addresses"; + +const OS_API_URL = "https://api.os.uk/search/places/v1/postcode"; +const OS_API_KEY = process.env.OS_API_KEY!; + +type OSPlacesItem = { DPA?: Record; LPI?: Record }; + +export interface OSPlacesResult { + status: number; + // First page response (kept for completeness) + data?: OSPlacesResponse; + // All results across pages (flattened) + results?: OSPlacesItem[]; + error?: string; +} + +/** + * Fetch a single page from OS Places + */ +async function fetchOsPlacesPage( + postcode: string, + offset: number, + maxResults: number, + retries: number, + delay: number +): Promise<{ status: number; data?: OSPlacesResponse; error?: string }> { + const url = `${OS_API_URL}?postcode=${encodeURIComponent( + postcode + )}&key=${OS_API_KEY}&maxresults=${maxResults}&offset=${offset}`; + + try { + const res = await fetch(url, { method: "GET" }); + + if (res.ok) { + const data: OSPlacesResponse = await res.json(); + return { status: res.status, data }; + } + + // Retry on transient issues (rate limit, server errors) + if ([429, 500, 503].includes(res.status) && retries > 0) { + await new Promise((r) => setTimeout(r, delay)); + return fetchOsPlacesPage( + postcode, + offset, + maxResults, + retries - 1, + delay * 2 + ); + } + + // Map known errors + let errorMessage = "Unexpected error"; + switch (res.status) { + case 400: + errorMessage = "Bad request — malformed postcode or query"; + break; + case 401: + errorMessage = "Unauthorized — check OS API key"; + break; + case 403: + errorMessage = "Forbidden — insufficient permissions for API access"; + break; + case 404: + errorMessage = "Postcode not found"; + break; + case 405: + errorMessage = "Method not allowed"; + break; + case 429: + errorMessage = "Rate limit exceeded — too many requests"; + break; + case 503: + errorMessage = "Service temporarily unavailable"; + break; + default: + errorMessage = `Unhandled error (${res.status})`; + } + return { status: res.status, error: errorMessage }; + } catch (err: any) { + if (retries > 0) { + await new Promise((r) => setTimeout(r, delay)); + return fetchOsPlacesPage( + postcode, + offset, + maxResults, + retries - 1, + delay * 2 + ); + } + return { status: 500, error: err?.message || "Network error" }; + } +} + +/** + * Calls the Ordnance Survey Places API for a given postcode, + * with offset-based pagination, retry handling, and structured errors. + */ +export async function lookupOsPlaces( + postcode: string, + { + maxResults = 100, + retries = 2, + delay = 1000, + }: { maxResults?: number; retries?: number; delay?: number } = {} +): Promise { + const normalized = postcode.toUpperCase().trim(); + + // Page 1 + const first = await fetchOsPlacesPage( + normalized, + 0, + maxResults, + retries, + delay + ); + if (first.error || !first.data) { + return { status: first.status, error: first.error }; + } + + const total = + first.data.header?.totalresults ?? first.data.results?.length ?? 0; + let allResults: OSPlacesItem[] = first.data.results ?? []; + + // If more pages exist, fetch them in a loop + for (let offset = maxResults; offset < total; offset += maxResults) { + const page = await fetchOsPlacesPage( + normalized, + offset, + maxResults, + retries, + delay + ); + if (page.error || !page.data) { + // Return what we have so far but indicate partial failure + return { + status: page.status, + data: first.data, + results: allResults, + error: `Failed to fetch page at offset ${offset}: ${page.error ?? "Unknown error"}`, + }; + } + if (page.data.results?.length) { + allResults = allResults.concat(page.data.results); + } + } + + return { status: 200, data: first.data, results: allResults }; +} diff --git a/src/app/api/postcode/OsPlacesToFlat.ts b/src/app/api/postcode/OsPlacesToFlat.ts new file mode 100644 index 0000000..0fcf860 --- /dev/null +++ b/src/app/api/postcode/OsPlacesToFlat.ts @@ -0,0 +1,28 @@ +// lib/osPlaces/mapper.ts +export type FlatAddress = { uprn: string; address: string }; + +export function mapOsPlacesToFlat( + results?: Array<{ DPA?: any; LPI?: any }> +): FlatAddress[] { + if (!results?.length) return []; + + const items = results + .map((r) => r.DPA ?? r.LPI) + .filter(Boolean) + .map((rec: any) => ({ + uprn: String(rec.UPRN ?? ""), + address: String(rec.ADDRESS ?? ""), + })) + .filter((x) => x.uprn && x.address); + + // de-dupe by UPRN (prefers first occurrence) + const seen = new Set(); + const deduped: FlatAddress[] = []; + for (const it of items) { + if (!seen.has(it.uprn)) { + seen.add(it.uprn); + deduped.push(it); + } + } + return deduped; +} diff --git a/src/app/api/postcode/[postcode]/addresses/route.ts b/src/app/api/postcode/[postcode]/addresses/route.ts new file mode 100644 index 0000000..df1fcf5 --- /dev/null +++ b/src/app/api/postcode/[postcode]/addresses/route.ts @@ -0,0 +1,83 @@ +import { NextResponse } from "next/server"; +import { db } from "@/app/db/db"; +import { postcodeSearch } from "@/app/db/schema/addresses"; +import { eq } from "drizzle-orm"; +import { lookupOsPlaces } from "@/app/api/postcode/LookupOsPlaces"; +import { mapOsPlacesToFlat } from "@/app/api/postcode/OsPlacesToFlat"; + +// Utility to normalize the postcode format +function normalizePostcode(postcode: string) { + return postcode.toUpperCase().replace(/\s+/g, ""); +} + +export async function GET( + _req: Request, + { params }: { params: { postcode: string } } +) { + const { postcode } = await params; + if (!postcode || typeof postcode !== "string") { + return NextResponse.json( + { error: "Missing or invalid postcode" }, + { status: 400 } + ); + } + + const normalized = normalizePostcode(postcode); + + try { + // Step 1: check cache + const cached = await db + .select() + .from(postcodeSearch) + .where(eq(postcodeSearch.postcode, normalized)) + .limit(1); + + if (cached.length > 0) { + const record = cached[0]; + const addresses = mapOsPlacesToFlat(record.resultData?.results); + return NextResponse.json({ + status: 200, + source: "cache", + total: record.resultData?.header?.totalresults ?? addresses.length, + results: addresses, + }); + } + + // Step 2: if no cache, query OS Places API + const result = await lookupOsPlaces(normalized); + if (result.error || result.status !== 200 || !result.data) { + return NextResponse.json( + { + error: result.error ?? "Failed to fetch address data", + status: result.status, + }, + { status: result.status } + ); + } + + console.log("Fetched OS Places data:", result); + + // Step 3: flatten and cache the result + const addresses = mapOsPlacesToFlat(result.results); + const total = result.data.header?.totalresults ?? addresses.length; + + await db.insert(postcodeSearch).values({ + postcode: normalized, + resultData: result.data, + }); + + // Step 4: return results + return NextResponse.json({ + status: 200, + source: "live", + total, + results: addresses, + }); + } catch (err: any) { + console.error("Error fetching OS Places data:", err); + return NextResponse.json( + { error: "Internal server error" }, + { status: 500 } + ); + } +} diff --git a/src/app/db/migrations/0120_watery_captain_america.sql b/src/app/db/migrations/0120_watery_captain_america.sql new file mode 100644 index 0000000..81d666a --- /dev/null +++ b/src/app/db/migrations/0120_watery_captain_america.sql @@ -0,0 +1,7 @@ +CREATE TABLE "postcode_search" ( + "id" serial PRIMARY KEY NOT NULL, + "postcode" text NOT NULL, + "result_data" jsonb NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL, + CONSTRAINT "postcode_search_postcode_unique" UNIQUE("postcode") +); diff --git a/src/app/db/migrations/meta/0120_snapshot.json b/src/app/db/migrations/meta/0120_snapshot.json new file mode 100644 index 0000000..5d78128 --- /dev/null +++ b/src/app/db/migrations/meta/0120_snapshot.json @@ -0,0 +1,3881 @@ +{ + "id": "1a54f67d-e4fa-40c7-ade9-ff2ba833793d", + "prevId": "7a977ad8-3cce-4478-aeb1-e920a98d4f32", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.postcode_search": { + "name": "postcode_search", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "result_data": { + "name": "result_data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "postcode_search_postcode_unique": { + "name": "postcode_search_postcode_unique", + "nullsNotDistinct": false, + "columns": [ + "postcode" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_status_tracker": { + "name": "property_status_tracker", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "hubspot_pipeline_id": { + "name": "hubspot_pipeline_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "property_status_tracker_property_id_property_id_fk": { + "name": "property_status_tracker_property_id_property_id_fk", + "tableFrom": "property_status_tracker", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "property_status_tracker_portfolio_id_portfolio_id_fk": { + "name": "property_status_tracker_portfolio_id_portfolio_id_fk", + "tableFrom": "property_status_tracker", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.energy_assessments": { + "name": "energy_assessments", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "uprn_source": { + "name": "uprn_source", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "property_type": { + "name": "property_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "building_reference_number": { + "name": "building_reference_number", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "current_energy_efficiency": { + "name": "current_energy_efficiency", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "current_energy_rating": { + "name": "current_energy_rating", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "address1": { + "name": "address1", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "address2": { + "name": "address2", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "address3": { + "name": "address3", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "posttown": { + "name": "posttown", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "address": { + "name": "address", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "county": { + "name": "county", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "constituency": { + "name": "constituency", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "constituency_label": { + "name": "constituency_label", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "low_energy_fixed_light_count": { + "name": "low_energy_fixed_light_count", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "construction_age_band": { + "name": "construction_age_band", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mainheat_energy_eff": { + "name": "mainheat_energy_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "windows_env_eff": { + "name": "windows_env_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "lighting_energy_eff": { + "name": "lighting_energy_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "environment_impact_potential": { + "name": "environment_impact_potential", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mainheatcont_description": { + "name": "mainheatcont_description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "sheating_energy_eff": { + "name": "sheating_energy_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "local_authority": { + "name": "local_authority", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "local_authority_label": { + "name": "local_authority_label", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "fixed_lighting_outlets_count": { + "name": "fixed_lighting_outlets_count", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "energy_tariff": { + "name": "energy_tariff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mechanical_ventilation": { + "name": "mechanical_ventilation", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "solar_water_heating_flag": { + "name": "solar_water_heating_flag", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "co2_emissions_potential": { + "name": "co2_emissions_potential", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "number_heated_rooms": { + "name": "number_heated_rooms", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "floor_description": { + "name": "floor_description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "energy_consumption_potential": { + "name": "energy_consumption_potential", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "built_form": { + "name": "built_form", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "number_open_fireplaces": { + "name": "number_open_fireplaces", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "windows_description": { + "name": "windows_description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "glazed_area": { + "name": "glazed_area", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "inspection_date": { + "name": "inspection_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true + }, + "mains_gas_flag": { + "name": "mains_gas_flag", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "co2_emiss_curr_per_floor_area": { + "name": "co2_emiss_curr_per_floor_area", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "heat_loss_corridor": { + "name": "heat_loss_corridor", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "unheated_corridor_length": { + "name": "unheated_corridor_length", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "flat_storey_count": { + "name": "flat_storey_count", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "roof_energy_eff": { + "name": "roof_energy_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "total_floor_area": { + "name": "total_floor_area", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "environment_impact_current": { + "name": "environment_impact_current", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "roof_description": { + "name": "roof_description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "floor_energy_eff": { + "name": "floor_energy_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "number_habitable_rooms": { + "name": "number_habitable_rooms", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "hot_water_env_eff": { + "name": "hot_water_env_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mainheatc_energy_eff": { + "name": "mainheatc_energy_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "main_fuel": { + "name": "main_fuel", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "lighting_env_eff": { + "name": "lighting_env_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "windows_energy_eff": { + "name": "windows_energy_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "floor_env_eff": { + "name": "floor_env_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "sheating_env_eff": { + "name": "sheating_env_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "lighting_description": { + "name": "lighting_description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "roof_env_eff": { + "name": "roof_env_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "walls_energy_eff": { + "name": "walls_energy_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "photo_supply": { + "name": "photo_supply", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "lighting_cost_potential": { + "name": "lighting_cost_potential", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mainheat_env_eff": { + "name": "mainheat_env_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "multi_glaze_proportion": { + "name": "multi_glaze_proportion", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "main_heating_controls": { + "name": "main_heating_controls", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "flat_top_storey": { + "name": "flat_top_storey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secondheat_description": { + "name": "secondheat_description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "walls_env_eff": { + "name": "walls_env_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "transaction_type": { + "name": "transaction_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "extension_count": { + "name": "extension_count", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mainheatc_env_eff": { + "name": "mainheatc_env_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "lmk_key": { + "name": "lmk_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "wind_turbine_count": { + "name": "wind_turbine_count", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tenure": { + "name": "tenure", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "floor_level": { + "name": "floor_level", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "potential_energy_efficiency": { + "name": "potential_energy_efficiency", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "potential_energy_rating": { + "name": "potential_energy_rating", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "hot_water_energy_eff": { + "name": "hot_water_energy_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "low_energy_lighting": { + "name": "low_energy_lighting", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "walls_description": { + "name": "walls_description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "hotwater_description": { + "name": "hotwater_description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "co2_emissions_current": { + "name": "co2_emissions_current", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "heating_cost_current": { + "name": "heating_cost_current", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "heating_cost_potential": { + "name": "heating_cost_potential", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "hot_water_cost_current": { + "name": "hot_water_cost_current", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "hot_water_cost_potential": { + "name": "hot_water_cost_potential", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "lighting_cost_current": { + "name": "lighting_cost_current", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "energy_consumption_current": { + "name": "energy_consumption_current", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "lodgement_date": { + "name": "lodgement_date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "lodgement_datetime": { + "name": "lodgement_datetime", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true + }, + "mainheat_description": { + "name": "mainheat_description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "floor_height": { + "name": "floor_height", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "glazed_type": { + "name": "glazed_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "file_location": { + "name": "file_location", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "surveyor_name": { + "name": "surveyor_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "surveyor_company": { + "name": "surveyor_company", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "space_heating_kwh": { + "name": "space_heating_kwh", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "water_heating_kwh": { + "name": "water_heating_kwh", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "number_of_doors": { + "name": "number_of_doors", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "number_of_insulated_doors": { + "name": "number_of_insulated_doors", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "number_of_floors": { + "name": "number_of_floors", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "insulation_wall_area": { + "name": "insulation_wall_area", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "heat_loss_perimeter": { + "name": "heat_loss_perimeter", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "party_wall_length": { + "name": "party_wall_length", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "perimeter": { + "name": "perimeter", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "rooms_with_bath_and_or_shower": { + "name": "rooms_with_bath_and_or_shower", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "rooms_with_mixer_shower_no_bath": { + "name": "rooms_with_mixer_shower_no_bath", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "room_with_bath_and_mixer_shower": { + "name": "room_with_bath_and_mixer_shower", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "percent_draftproofed": { + "name": "percent_draftproofed", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "has_hot_water_cylinder": { + "name": "has_hot_water_cylinder", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "cylinder_insulation_type": { + "name": "cylinder_insulation_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cylinder_insulation_thickness": { + "name": "cylinder_insulation_thickness", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cylinder_thermostat": { + "name": "cylinder_thermostat", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "main_dwelling_ground_floor_area": { + "name": "main_dwelling_ground_floor_area", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "number_of_windows": { + "name": "number_of_windows", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "windows_area": { + "name": "windows_area", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.energy_assessment_documents": { + "name": "energy_assessment_documents", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "energy_assessment_id": { + "name": "energy_assessment_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "document_type": { + "name": "document_type", + "type": "document_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "document_location": { + "name": "document_location", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "scenario_id": { + "name": "scenario_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "energy_assessment_documents_energy_assessment_id_energy_assessments_id_fk": { + "name": "energy_assessment_documents_energy_assessment_id_energy_assessments_id_fk", + "tableFrom": "energy_assessment_documents", + "tableTo": "energy_assessments", + "columnsFrom": [ + "energy_assessment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "energy_assessment_documents_scenario_id_energy_assessment_scenarios_id_fk": { + "name": "energy_assessment_documents_scenario_id_energy_assessment_scenarios_id_fk", + "tableFrom": "energy_assessment_documents", + "tableTo": "energy_assessment_scenarios", + "columnsFrom": [ + "scenario_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.energy_assessment_scenarios": { + "name": "energy_assessment_scenarios", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "scenario_name": { + "name": "scenario_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "energy_assessment_id": { + "name": "energy_assessment_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "energy_assessment_scenarios_energy_assessment_id_energy_assessments_id_fk": { + "name": "energy_assessment_scenarios_energy_assessment_id_energy_assessments_id_fk", + "tableFrom": "energy_assessment_scenarios", + "tableTo": "energy_assessments", + "columnsFrom": [ + "energy_assessment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.funding_package": { + "name": "funding_package", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "plan_id": { + "name": "plan_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "scheme": { + "name": "scheme", + "type": "scheme", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "project_funding": { + "name": "project_funding", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "total_uplift": { + "name": "total_uplift", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "full_project_score": { + "name": "full_project_score", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "partial_project_score": { + "name": "partial_project_score", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "uplift_project_score": { + "name": "uplift_project_score", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "funding_package_plan_id_plan_id_fk": { + "name": "funding_package_plan_id_plan_id_fk", + "tableFrom": "funding_package", + "tableTo": "plan", + "columnsFrom": [ + "plan_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.funding_package_measures": { + "name": "funding_package_measures", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "funding_package_id": { + "name": "funding_package_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "measure": { + "name": "measure", + "type": "type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "material_id": { + "name": "material_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "innovation_uplift": { + "name": "innovation_uplift", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "partial_project_score": { + "name": "partial_project_score", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "uplift_project_score": { + "name": "uplift_project_score", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "funding_package_measures_funding_package_id_funding_package_id_fk": { + "name": "funding_package_measures_funding_package_id_funding_package_id_fk", + "tableFrom": "funding_package_measures", + "tableTo": "funding_package", + "columnsFrom": [ + "funding_package_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "funding_package_measures_material_id_material_id_fk": { + "name": "funding_package_measures_material_id_material_id_fk", + "tableFrom": "funding_package_measures", + "tableTo": "material", + "columnsFrom": [ + "material_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.material": { + "name": "material", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "depth": { + "name": "depth", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "depth_unit": { + "name": "depth_unit", + "type": "depth_unit", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "cost_unit": { + "name": "cost_unit", + "type": "cost_unit", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "r_value_per_mm": { + "name": "r_value_per_mm", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "r_value_unit": { + "name": "r_value_unit", + "type": "r_value_unit", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "thermal_conductivity": { + "name": "thermal_conductivity", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "thermal_conductivity_unit": { + "name": "thermal_conductivity_unit", + "type": "thermal_conductivity_unit", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "link": { + "name": "link", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "prime_material_cost": { + "name": "prime_material_cost", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "material_cost": { + "name": "material_cost", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "labour_cost": { + "name": "labour_cost", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "labour_hours_per_unit": { + "name": "labour_hours_per_unit", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "plant_cost": { + "name": "plant_cost", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "total_cost": { + "name": "total_cost", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cost": { + "name": "cost", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_installer_quote": { + "name": "is_installer_quote", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "innovation_rate": { + "name": "innovation_rate", + "type": "real", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "size": { + "name": "size", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "size_unit": { + "name": "size_unit", + "type": "size_unit", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "includes_scaffolding": { + "name": "includes_scaffolding", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "includes_battery": { + "name": "includes_battery", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "battery_size": { + "name": "battery_size", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.portfolio": { + "name": "portfolio", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "budget": { + "name": "budget", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "goal": { + "name": "goal", + "type": "goal", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "cost": { + "name": "cost", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "number_of_properties": { + "name": "number_of_properties", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "co2_equivalent_savings": { + "name": "co2_equivalent_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_savings": { + "name": "energy_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_cost_savings": { + "name": "energy_cost_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "property_valuation_increase": { + "name": "property_valuation_increase", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "rental_yield_increase": { + "name": "rental_yield_increase", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "total_work_hours": { + "name": "total_work_hours", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "labour_days": { + "name": "labour_days", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "epc_breakdown_pre_retrofit": { + "name": "epc_breakdown_pre_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_breakdown_post_retrofit": { + "name": "epc_breakdown_post_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "n_units_to_retrofit": { + "name": "n_units_to_retrofit", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "co2_per_unit_pre_retrofit": { + "name": "co2_per_unit_pre_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "co2_per_unit_post_retrofit": { + "name": "co2_per_unit_post_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "energy_bill_per_unit_pre_retrofit": { + "name": "energy_bill_per_unit_pre_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "energy_bill_per_unit_post_retrofit": { + "name": "energy_bill_per_unit_post_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "energy_consumption_per_unit_pre_retrofit": { + "name": "energy_consumption_per_unit_pre_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "energy_consumption_per_unit_post_retrofit": { + "name": "energy_consumption_per_unit_post_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "valuation_improvement_per_unit": { + "name": "valuation_improvement_per_unit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cost_per_unit": { + "name": "cost_per_unit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cost_per_co2_saved": { + "name": "cost_per_co2_saved", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cost_per_sap_point": { + "name": "cost_per_sap_point", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "valuation_return_on_investment": { + "name": "valuation_return_on_investment", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.portfolioUsers": { + "name": "portfolioUsers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "portfolioUsers_user_id_user_id_fk": { + "name": "portfolioUsers_user_id_user_id_fk", + "tableFrom": "portfolioUsers", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "portfolioUsers_portfolio_id_portfolio_id_fk": { + "name": "portfolioUsers_portfolio_id_portfolio_id_fk", + "tableFrom": "portfolioUsers", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.non_intrusive_survey": { + "name": "non_intrusive_survey", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "survey_date": { + "name": "survey_date", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "surveyor": { + "name": "surveyor", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.non_intrusive_survey_notes": { + "name": "non_intrusive_survey_notes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "survey_id": { + "name": "survey_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "non_intrusive_survey_notes_survey_id_non_intrusive_survey_id_fk": { + "name": "non_intrusive_survey_notes_survey_id_non_intrusive_survey_id_fk", + "tableFrom": "non_intrusive_survey_notes", + "tableTo": "non_intrusive_survey", + "columnsFrom": [ + "survey_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property": { + "name": "property", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "creation_status": { + "name": "creation_status", + "type": "creation_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "building_reference_number": { + "name": "building_reference_number", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "status", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "address": { + "name": "address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "has_pre_condition_report": { + "name": "has_pre_condition_report", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "has_recommendations": { + "name": "has_recommendations", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "property_type": { + "name": "property_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "built_form": { + "name": "built_form", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "local_authority": { + "name": "local_authority", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "constituency": { + "name": "constituency", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "number_of_rooms": { + "name": "number_of_rooms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "year_built": { + "name": "year_built", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tenure": { + "name": "tenure", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "current_epc_rating": { + "name": "current_epc_rating", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "current_sap_points": { + "name": "current_sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "current_valuation": { + "name": "current_valuation", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "property_portfolio_id_portfolio_id_fk": { + "name": "property_portfolio_id_portfolio_id_fk", + "tableFrom": "property", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_details_epc": { + "name": "property_details_epc", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "full_address": { + "name": "full_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "total_floor_area": { + "name": "total_floor_area", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "walls": { + "name": "walls", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "walls_rating": { + "name": "walls_rating", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "roof": { + "name": "roof", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "roof_rating": { + "name": "roof_rating", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "floor": { + "name": "floor", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "floor_rating": { + "name": "floor_rating", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "windows": { + "name": "windows", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "windows_rating": { + "name": "windows_rating", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "heating": { + "name": "heating", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "heating_rating": { + "name": "heating_rating", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "heating_controls": { + "name": "heating_controls", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "heating_controls_rating": { + "name": "heating_controls_rating", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "hot_water": { + "name": "hot_water", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "hot_water_rating": { + "name": "hot_water_rating", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "lighting": { + "name": "lighting", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lighting_rating": { + "name": "lighting_rating", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "mainfuel": { + "name": "mainfuel", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ventilation": { + "name": "ventilation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "solar_pv": { + "name": "solar_pv", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "solar_hot_water": { + "name": "solar_hot_water", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "wind_turbine": { + "name": "wind_turbine", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "floor_height": { + "name": "floor_height", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "number_heated_rooms": { + "name": "number_heated_rooms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heat_loss_corridor": { + "name": "heat_loss_corridor", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "unheated_corridor_length": { + "name": "unheated_corridor_length", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "number_of_open_fireplaces": { + "name": "number_of_open_fireplaces", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "number_of_extensions": { + "name": "number_of_extensions", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "number_of_storeys": { + "name": "number_of_storeys", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mains_gas": { + "name": "mains_gas", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "energy_tariff": { + "name": "energy_tariff", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "primary_energy_consumption": { + "name": "primary_energy_consumption", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_emissions": { + "name": "co2_emissions", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "current_energy_demand": { + "name": "current_energy_demand", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "current_energy_demand_heating_hotwater": { + "name": "current_energy_demand_heating_hotwater", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "estimated": { + "name": "estimated", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "heating_cost_current": { + "name": "heating_cost_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "hot_water_cost_current": { + "name": "hot_water_cost_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lighting_cost_current": { + "name": "lighting_cost_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "appliances_cost_current": { + "name": "appliances_cost_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "gas_standing_charge": { + "name": "gas_standing_charge", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "electricity_standing_charge": { + "name": "electricity_standing_charge", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "property_details_epc_property_id_property_id_fk": { + "name": "property_details_epc_property_id_property_id_fk", + "tableFrom": "property_details_epc", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "property_details_epc_portfolio_id_portfolio_id_fk": { + "name": "property_details_epc_portfolio_id_portfolio_id_fk", + "tableFrom": "property_details_epc", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_details_meter": { + "name": "property_details_meter", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "energy_supplier": { + "name": "energy_supplier", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gas_supplier": { + "name": "gas_supplier", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "meter_reading_total": { + "name": "meter_reading_total", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "meter_reading_electricity": { + "name": "meter_reading_electricity", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "meter_reading_gas": { + "name": "meter_reading_gas", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_details_spatial": { + "name": "property_details_spatial", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "x_coordinate": { + "name": "x_coordinate", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "y_coordinate": { + "name": "y_coordinate", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "latitude": { + "name": "latitude", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "longitude": { + "name": "longitude", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "conservation_status": { + "name": "conservation_status", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "is_listed_building": { + "name": "is_listed_building", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "is_heritage_building": { + "name": "is_heritage_building", + "type": "boolean", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_targets": { + "name": "property_targets", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "epc": { + "name": "epc", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "heat_demand": { + "name": "heat_demand", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "property_targets_property_id_property_id_fk": { + "name": "property_targets_property_id_property_id_fk", + "tableFrom": "property_targets", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "property_targets_portfolio_id_portfolio_id_fk": { + "name": "property_targets_portfolio_id_portfolio_id_fk", + "tableFrom": "property_targets", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.plan": { + "name": "plan", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "scenario_id": { + "name": "scenario_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "is_default": { + "name": "is_default", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "valuation_increase_lower_bound": { + "name": "valuation_increase_lower_bound", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "valuation_increase_upper_bound": { + "name": "valuation_increase_upper_bound", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "valuation_increase_average": { + "name": "valuation_increase_average", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "plan_portfolio_id_portfolio_id_fk": { + "name": "plan_portfolio_id_portfolio_id_fk", + "tableFrom": "plan", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "plan_property_id_property_id_fk": { + "name": "plan_property_id_property_id_fk", + "tableFrom": "plan", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "plan_scenario_id_scenario_id_fk": { + "name": "plan_scenario_id_scenario_id_fk", + "tableFrom": "plan", + "tableTo": "scenario", + "columnsFrom": [ + "scenario_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.plan_recommendations": { + "name": "plan_recommendations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "plan_id": { + "name": "plan_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "recommendation_id": { + "name": "recommendation_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "plan_recommendations_plan_id_plan_id_fk": { + "name": "plan_recommendations_plan_id_plan_id_fk", + "tableFrom": "plan_recommendations", + "tableTo": "plan", + "columnsFrom": [ + "plan_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "plan_recommendations_recommendation_id_recommendation_id_fk": { + "name": "plan_recommendations_recommendation_id_recommendation_id_fk", + "tableFrom": "plan_recommendations", + "tableTo": "recommendation", + "columnsFrom": [ + "recommendation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.recommendation": { + "name": "recommendation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "measure_type": { + "name": "measure_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "estimated_cost": { + "name": "estimated_cost", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "contingency_cost": { + "name": "contingency_cost", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "default": { + "name": "default", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "starting_u_value": { + "name": "starting_u_value", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "new_u_value": { + "name": "new_u_value", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "sap_points": { + "name": "sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "heat_demand": { + "name": "heat_demand", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "kwh_savings": { + "name": "kwh_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_equivalent_savings": { + "name": "co2_equivalent_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_savings": { + "name": "energy_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_cost_savings": { + "name": "energy_cost_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "property_valuation_increase": { + "name": "property_valuation_increase", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "rental_yield_increase": { + "name": "rental_yield_increase", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "total_work_hours": { + "name": "total_work_hours", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "labour_days": { + "name": "labour_days", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "already_installed": { + "name": "already_installed", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "recommendation_property_id_property_id_fk": { + "name": "recommendation_property_id_property_id_fk", + "tableFrom": "recommendation", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.recommendation_materials": { + "name": "recommendation_materials", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "recommendation_id": { + "name": "recommendation_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "material_id": { + "name": "material_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "depth": { + "name": "depth", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "quantity": { + "name": "quantity", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "quantity_unit": { + "name": "quantity_unit", + "type": "unit_quantity", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "estimated_cost": { + "name": "estimated_cost", + "type": "real", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "recommendation_materials_recommendation_id_recommendation_id_fk": { + "name": "recommendation_materials_recommendation_id_recommendation_id_fk", + "tableFrom": "recommendation_materials", + "tableTo": "recommendation", + "columnsFrom": [ + "recommendation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "recommendation_materials_material_id_material_id_fk": { + "name": "recommendation_materials_material_id_material_id_fk", + "tableFrom": "recommendation_materials", + "tableTo": "material", + "columnsFrom": [ + "material_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.scenario": { + "name": "scenario", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "budget": { + "name": "budget", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "housing_type": { + "name": "housing_type", + "type": "housing_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "goal": { + "name": "goal", + "type": "goal", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "goal_value": { + "name": "goal_value", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ashp_cop": { + "name": "ashp_cop", + "type": "real", + "primaryKey": false, + "notNull": false, + "default": 2.8 + }, + "trigger_file_path": { + "name": "trigger_file_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "already_installed_file_path": { + "name": "already_installed_file_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "patches_file_path": { + "name": "patches_file_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "non_invasive_recommendations_file_path": { + "name": "non_invasive_recommendations_file_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "exclusions": { + "name": "exclusions", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "multi_plan": { + "name": "multi_plan", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "is_default": { + "name": "is_default", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "cost": { + "name": "cost", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "contingency": { + "name": "contingency", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "funding": { + "name": "funding", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "total_work_hours": { + "name": "total_work_hours", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_savings": { + "name": "energy_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_equivalent_savings": { + "name": "co2_equivalent_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_cost_savings": { + "name": "energy_cost_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "property_valuation_increase": { + "name": "property_valuation_increase", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "labour_days": { + "name": "labour_days", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "epc_breakdown_pre_retrofit": { + "name": "epc_breakdown_pre_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_breakdown_post_retrofit": { + "name": "epc_breakdown_post_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "number_of_properties": { + "name": "number_of_properties", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "n_units_to_retrofit": { + "name": "n_units_to_retrofit", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "co2_per_unit_pre_retrofit": { + "name": "co2_per_unit_pre_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "co2_per_unit_post_retrofit": { + "name": "co2_per_unit_post_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "energy_bill_per_unit_pre_retrofit": { + "name": "energy_bill_per_unit_pre_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "energy_bill_per_unit_post_retrofit": { + "name": "energy_bill_per_unit_post_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "energy_consumption_per_unit_pre_retrofit": { + "name": "energy_consumption_per_unit_pre_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "energy_consumption_per_unit_post_retrofit": { + "name": "energy_consumption_per_unit_post_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "valuation_improvement_per_unit": { + "name": "valuation_improvement_per_unit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cost_per_unit": { + "name": "cost_per_unit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cost_per_co2_saved": { + "name": "cost_per_co2_saved", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cost_per_sap_point": { + "name": "cost_per_sap_point", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "valuation_return_on_investment": { + "name": "valuation_return_on_investment", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "scenario_portfolio_id_portfolio_id_fk": { + "name": "scenario_portfolio_id_portfolio_id_fk", + "tableFrom": "scenario", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.solar": { + "name": "solar", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "longitude": { + "name": "longitude", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "latitude": { + "name": "latitude", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "google_api_response": { + "name": "google_api_response", + "type": "jsonb", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.solar_scenario": { + "name": "solar_scenario", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "solar_id": { + "name": "solar_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "scenario_type": { + "name": "scenario_type", + "type": "scenario_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "number_panels": { + "name": "number_panels", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "array_kwhp": { + "name": "array_kwhp", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "lifetime_dc_kwh": { + "name": "lifetime_dc_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "yearly_dc_kwh": { + "name": "yearly_dc_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "lifetime_ac_kwh": { + "name": "lifetime_ac_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "yearly_ac_kwh": { + "name": "yearly_ac_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cost": { + "name": "cost", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "expected_payback_years": { + "name": "expected_payback_years", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "panelled_roof_area": { + "name": "panelled_roof_area", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "is_default": { + "name": "is_default", + "type": "boolean", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "solar_scenario_solar_id_solar_id_fk": { + "name": "solar_scenario_solar_id_solar_id_fk", + "tableFrom": "solar_scenario", + "tableTo": "solar", + "columnsFrom": [ + "solar_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.account": { + "name": "account", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "name": "account_provider_providerAccountId_pk", + "columns": [ + "provider", + "providerAccountId" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "firstName": { + "name": "firstName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "emailVerified": { + "name": "emailVerified", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "oauth_id": { + "name": "oauth_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "oauth_provider": { + "name": "oauth_provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "onboarded": { + "name": "onboarded", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "last_login": { + "name": "last_login", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_profiles": { + "name": "user_profiles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "user_type": { + "name": "user_type", + "type": "user_profiles_user_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "property_count": { + "name": "property_count", + "type": "user_profiles_property_count", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "goals": { + "name": "goals", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "referral_source": { + "name": "referral_source", + "type": "user_profiles_referral_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "nrla_membership_id": { + "name": "nrla_membership_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "accepted_privacy": { + "name": "accepted_privacy", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "accepted_privacy_at": { + "name": "accepted_privacy_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "marketing_opt_in": { + "name": "marketing_opt_in", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "marketing_opt_in_at": { + "name": "marketing_opt_in_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_profiles_user_id_user_id_fk": { + "name": "user_profiles_user_id_user_id_fk", + "tableFrom": "user_profiles", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verificationToken": { + "name": "verificationToken", + "schema": "", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.document_type": { + "name": "document_type", + "schema": "public", + "values": [ + "EPR", + "Condition Report", + "Evidence Report", + "Summary Information", + "Floor Plan", + "Scenario Draft EPC", + "Scenario Site Notes" + ] + }, + "public.scheme": { + "name": "scheme", + "schema": "public", + "values": [ + "eco4", + "gbis", + "whlg", + "none" + ] + }, + "public.cost_unit": { + "name": "cost_unit", + "schema": "public", + "values": [ + "gbp_sq_meter", + "gbp_per_unit", + "gbp_per_m2", + "gbp_per_m" + ] + }, + "public.depth_unit": { + "name": "depth_unit", + "schema": "public", + "values": [ + "mm" + ] + }, + "public.type": { + "name": "type", + "schema": "public", + "values": [ + "suspended_floor_insulation", + "solid_floor_insulation", + "external_wall_insulation", + "internal_wall_insulation", + "cavity_wall_insulation", + "mechanical_ventilation", + "loft_insulation", + "exposed_floor_insulation", + "flat_roof_insulation", + "room_roof_insulation", + "cavity_wall_extraction", + "iwi_wall_demolition", + "iwi_vapour_barrier", + "iwi_redecoration", + "suspended_floor_demolition", + "suspended_floor_redecoration", + "suspended_floor_vapour_barrier", + "solid_floor_demolition", + "solid_floor_preparation", + "solid_floor_vapour_barrier", + "solid_floor_redecoration", + "ewi_wall_demolition", + "ewi_wall_preparation", + "ewi_wall_redecoration", + "low_energy_lighting_installation", + "flat_roof_preparation", + "flat_roof_vapour_barrier", + "flat_roof_waterproofing", + "windows_glazing", + "trickle_vent", + "door_undercut", + "solar_pv", + "solar_battery", + "scaffolding", + "high_heat_retention_storage_heaters", + "air_source_heat_pump", + "roomstat_programmer_trvs", + "time_temperature_zone_control", + "sealing_fireplace" + ] + }, + "public.r_value_unit": { + "name": "r_value_unit", + "schema": "public", + "values": [ + "square_meter_kelvin_per_watt" + ] + }, + "public.size_unit": { + "name": "size_unit", + "schema": "public", + "values": [ + "kWp", + "kW", + "watt", + "storey" + ] + }, + "public.thermal_conductivity_unit": { + "name": "thermal_conductivity_unit", + "schema": "public", + "values": [ + "watt_per_meter_kelvin" + ] + }, + "public.goal": { + "name": "goal", + "schema": "public", + "values": [ + "Valuation Improvement", + "Increasing EPC", + "Reducing CO2 emissions", + "Energy Savings", + "None" + ] + }, + "public.role": { + "name": "role", + "schema": "public", + "values": [ + "creator", + "admin", + "read", + "write" + ] + }, + "public.status": { + "name": "status", + "schema": "public", + "values": [ + "scoping", + "survey", + "assessment", + "tendering", + "project underway", + "completion; status: on track", + "completion; status: delayed", + "completion; status: at risk", + "completion; status: completed", + "needs review" + ] + }, + "public.epc": { + "name": "epc", + "schema": "public", + "values": [ + "A", + "B", + "C", + "D", + "E", + "F", + "G" + ] + }, + "public.creation_status": { + "name": "creation_status", + "schema": "public", + "values": [ + "LOADING", + "READY", + "ERROR" + ] + }, + "public.housing_type": { + "name": "housing_type", + "schema": "public", + "values": [ + "Private", + "Social" + ] + }, + "public.unit_quantity": { + "name": "unit_quantity", + "schema": "public", + "values": [ + "m2", + "part", + "kwp" + ] + }, + "public.scenario_type": { + "name": "scenario_type", + "schema": "public", + "values": [ + "unit", + "building" + ] + }, + "public.user_profiles_property_count": { + "name": "user_profiles_property_count", + "schema": "public", + "values": [ + "1", + "2–5", + "6–20", + "21+", + "1–50", + "51–100", + "101–300", + "301–1000", + "1000+" + ] + }, + "public.user_profiles_referral_source": { + "name": "user_profiles_referral_source", + "schema": "public", + "values": [ + "search", + "social_media", + "NRLA", + "partner", + "word_of_mouth", + "other" + ] + }, + "public.user_profiles_user_type": { + "name": "user_profiles_user_type", + "schema": "public", + "values": [ + "private_landlord", + "private_tenant", + "social_landlord", + "social_tenant", + "homeowner", + "other" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/src/app/db/schema/addresses.ts b/src/app/db/schema/addresses.ts new file mode 100644 index 0000000..801a80c --- /dev/null +++ b/src/app/db/schema/addresses.ts @@ -0,0 +1,35 @@ +import { pgTable, serial, text, jsonb, timestamp } from "drizzle-orm/pg-core"; + +// This table stores postcode search results from the OS Places API +// for re-use and caching purposes. The data is stored in jsonb format, to +// allow for fast queries and flexibility with the API response structure. + +export interface OSPlacesHeader { + totalresults?: number; + offset?: number; + maxresults?: number; + [k: string]: any; +} + +export interface OSPlacesItem { + DPA?: Record; + LPI?: Record; +} + +export interface OSPlacesResponse { + header?: OSPlacesHeader; + results?: OSPlacesItem[]; +} + +export const postcodeSearch = pgTable("postcode_search", { + id: serial("id").primaryKey(), + + // Normalized postcode (uppercase, no spaces) + postcode: text("postcode").notNull().unique(), + + // Full OS Places API response + resultData: jsonb("result_data").$type().notNull(), + + // Timestamp for when the entry was first created + createdAt: timestamp("created_at").defaultNow().notNull(), +}); From 72b04ee2bdc1eb22b8f6f737ca15bd5b7fb4506e Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Thu, 23 Oct 2025 11:12:21 +0000 Subject: [PATCH 10/15] reverted migrations --- .../0120_watery_captain_america.sql | 7 - src/app/db/migrations/meta/0120_snapshot.json | 3881 ----------------- src/app/db/migrations/meta/_journal.json | 9 +- 3 files changed, 1 insertion(+), 3896 deletions(-) delete mode 100644 src/app/db/migrations/0120_watery_captain_america.sql delete mode 100644 src/app/db/migrations/meta/0120_snapshot.json diff --git a/src/app/db/migrations/0120_watery_captain_america.sql b/src/app/db/migrations/0120_watery_captain_america.sql deleted file mode 100644 index 81d666a..0000000 --- a/src/app/db/migrations/0120_watery_captain_america.sql +++ /dev/null @@ -1,7 +0,0 @@ -CREATE TABLE "postcode_search" ( - "id" serial PRIMARY KEY NOT NULL, - "postcode" text NOT NULL, - "result_data" jsonb NOT NULL, - "created_at" timestamp DEFAULT now() NOT NULL, - CONSTRAINT "postcode_search_postcode_unique" UNIQUE("postcode") -); diff --git a/src/app/db/migrations/meta/0120_snapshot.json b/src/app/db/migrations/meta/0120_snapshot.json deleted file mode 100644 index 5d78128..0000000 --- a/src/app/db/migrations/meta/0120_snapshot.json +++ /dev/null @@ -1,3881 +0,0 @@ -{ - "id": "1a54f67d-e4fa-40c7-ade9-ff2ba833793d", - "prevId": "7a977ad8-3cce-4478-aeb1-e920a98d4f32", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.postcode_search": { - "name": "postcode_search", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "postcode": { - "name": "postcode", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "result_data": { - "name": "result_data", - "type": "jsonb", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "postcode_search_postcode_unique": { - "name": "postcode_search_postcode_unique", - "nullsNotDistinct": false, - "columns": [ - "postcode" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.property_status_tracker": { - "name": "property_status_tracker", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "hubspot_deal_id": { - "name": "hubspot_deal_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "property_id": { - "name": "property_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "portfolio_id": { - "name": "portfolio_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "hubspot_pipeline_id": { - "name": "hubspot_pipeline_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp (6) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp (6) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "property_status_tracker_property_id_property_id_fk": { - "name": "property_status_tracker_property_id_property_id_fk", - "tableFrom": "property_status_tracker", - "tableTo": "property", - "columnsFrom": [ - "property_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "property_status_tracker_portfolio_id_portfolio_id_fk": { - "name": "property_status_tracker_portfolio_id_portfolio_id_fk", - "tableFrom": "property_status_tracker", - "tableTo": "portfolio", - "columnsFrom": [ - "portfolio_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.energy_assessments": { - "name": "energy_assessments", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "uprn": { - "name": "uprn", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "uprn_source": { - "name": "uprn_source", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "property_type": { - "name": "property_type", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "building_reference_number": { - "name": "building_reference_number", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "current_energy_efficiency": { - "name": "current_energy_efficiency", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "current_energy_rating": { - "name": "current_energy_rating", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "address1": { - "name": "address1", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "address2": { - "name": "address2", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "address3": { - "name": "address3", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "posttown": { - "name": "posttown", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "postcode": { - "name": "postcode", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "address": { - "name": "address", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "county": { - "name": "county", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "constituency": { - "name": "constituency", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "constituency_label": { - "name": "constituency_label", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "low_energy_fixed_light_count": { - "name": "low_energy_fixed_light_count", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "construction_age_band": { - "name": "construction_age_band", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "mainheat_energy_eff": { - "name": "mainheat_energy_eff", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "windows_env_eff": { - "name": "windows_env_eff", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "lighting_energy_eff": { - "name": "lighting_energy_eff", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "environment_impact_potential": { - "name": "environment_impact_potential", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "mainheatcont_description": { - "name": "mainheatcont_description", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "sheating_energy_eff": { - "name": "sheating_energy_eff", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "local_authority": { - "name": "local_authority", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "local_authority_label": { - "name": "local_authority_label", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "fixed_lighting_outlets_count": { - "name": "fixed_lighting_outlets_count", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "energy_tariff": { - "name": "energy_tariff", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "mechanical_ventilation": { - "name": "mechanical_ventilation", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "solar_water_heating_flag": { - "name": "solar_water_heating_flag", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "co2_emissions_potential": { - "name": "co2_emissions_potential", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "number_heated_rooms": { - "name": "number_heated_rooms", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "floor_description": { - "name": "floor_description", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "energy_consumption_potential": { - "name": "energy_consumption_potential", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "built_form": { - "name": "built_form", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "number_open_fireplaces": { - "name": "number_open_fireplaces", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "windows_description": { - "name": "windows_description", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "glazed_area": { - "name": "glazed_area", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "inspection_date": { - "name": "inspection_date", - "type": "timestamp (6) with time zone", - "primaryKey": false, - "notNull": true - }, - "mains_gas_flag": { - "name": "mains_gas_flag", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "co2_emiss_curr_per_floor_area": { - "name": "co2_emiss_curr_per_floor_area", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "heat_loss_corridor": { - "name": "heat_loss_corridor", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "unheated_corridor_length": { - "name": "unheated_corridor_length", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "flat_storey_count": { - "name": "flat_storey_count", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "roof_energy_eff": { - "name": "roof_energy_eff", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "total_floor_area": { - "name": "total_floor_area", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "environment_impact_current": { - "name": "environment_impact_current", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "roof_description": { - "name": "roof_description", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "floor_energy_eff": { - "name": "floor_energy_eff", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "number_habitable_rooms": { - "name": "number_habitable_rooms", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "hot_water_env_eff": { - "name": "hot_water_env_eff", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "mainheatc_energy_eff": { - "name": "mainheatc_energy_eff", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "main_fuel": { - "name": "main_fuel", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "lighting_env_eff": { - "name": "lighting_env_eff", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "windows_energy_eff": { - "name": "windows_energy_eff", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "floor_env_eff": { - "name": "floor_env_eff", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "sheating_env_eff": { - "name": "sheating_env_eff", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "lighting_description": { - "name": "lighting_description", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "roof_env_eff": { - "name": "roof_env_eff", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "walls_energy_eff": { - "name": "walls_energy_eff", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "photo_supply": { - "name": "photo_supply", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "lighting_cost_potential": { - "name": "lighting_cost_potential", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "mainheat_env_eff": { - "name": "mainheat_env_eff", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "multi_glaze_proportion": { - "name": "multi_glaze_proportion", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "main_heating_controls": { - "name": "main_heating_controls", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "flat_top_storey": { - "name": "flat_top_storey", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "secondheat_description": { - "name": "secondheat_description", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "walls_env_eff": { - "name": "walls_env_eff", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "transaction_type": { - "name": "transaction_type", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "extension_count": { - "name": "extension_count", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "mainheatc_env_eff": { - "name": "mainheatc_env_eff", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "lmk_key": { - "name": "lmk_key", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "wind_turbine_count": { - "name": "wind_turbine_count", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "tenure": { - "name": "tenure", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "floor_level": { - "name": "floor_level", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "potential_energy_efficiency": { - "name": "potential_energy_efficiency", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "potential_energy_rating": { - "name": "potential_energy_rating", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "hot_water_energy_eff": { - "name": "hot_water_energy_eff", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "low_energy_lighting": { - "name": "low_energy_lighting", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "walls_description": { - "name": "walls_description", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "hotwater_description": { - "name": "hotwater_description", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "co2_emissions_current": { - "name": "co2_emissions_current", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "heating_cost_current": { - "name": "heating_cost_current", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "heating_cost_potential": { - "name": "heating_cost_potential", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "hot_water_cost_current": { - "name": "hot_water_cost_current", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "hot_water_cost_potential": { - "name": "hot_water_cost_potential", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "lighting_cost_current": { - "name": "lighting_cost_current", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "energy_consumption_current": { - "name": "energy_consumption_current", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "lodgement_date": { - "name": "lodgement_date", - "type": "date", - "primaryKey": false, - "notNull": true - }, - "lodgement_datetime": { - "name": "lodgement_datetime", - "type": "timestamp (6)", - "primaryKey": false, - "notNull": true - }, - "mainheat_description": { - "name": "mainheat_description", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "floor_height": { - "name": "floor_height", - "type": "real", - "primaryKey": false, - "notNull": true - }, - "glazed_type": { - "name": "glazed_type", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "file_location": { - "name": "file_location", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "surveyor_name": { - "name": "surveyor_name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "surveyor_company": { - "name": "surveyor_company", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "space_heating_kwh": { - "name": "space_heating_kwh", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "water_heating_kwh": { - "name": "water_heating_kwh", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "number_of_doors": { - "name": "number_of_doors", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "number_of_insulated_doors": { - "name": "number_of_insulated_doors", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "number_of_floors": { - "name": "number_of_floors", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "insulation_wall_area": { - "name": "insulation_wall_area", - "type": "real", - "primaryKey": false, - "notNull": true - }, - "heat_loss_perimeter": { - "name": "heat_loss_perimeter", - "type": "real", - "primaryKey": false, - "notNull": true - }, - "party_wall_length": { - "name": "party_wall_length", - "type": "real", - "primaryKey": false, - "notNull": true - }, - "perimeter": { - "name": "perimeter", - "type": "real", - "primaryKey": false, - "notNull": true - }, - "rooms_with_bath_and_or_shower": { - "name": "rooms_with_bath_and_or_shower", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "rooms_with_mixer_shower_no_bath": { - "name": "rooms_with_mixer_shower_no_bath", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "room_with_bath_and_mixer_shower": { - "name": "room_with_bath_and_mixer_shower", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "percent_draftproofed": { - "name": "percent_draftproofed", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "has_hot_water_cylinder": { - "name": "has_hot_water_cylinder", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "cylinder_insulation_type": { - "name": "cylinder_insulation_type", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cylinder_insulation_thickness": { - "name": "cylinder_insulation_thickness", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "cylinder_thermostat": { - "name": "cylinder_thermostat", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "main_dwelling_ground_floor_area": { - "name": "main_dwelling_ground_floor_area", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "number_of_windows": { - "name": "number_of_windows", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "windows_area": { - "name": "windows_area", - "type": "real", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.energy_assessment_documents": { - "name": "energy_assessment_documents", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "uprn": { - "name": "uprn", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "energy_assessment_id": { - "name": "energy_assessment_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "document_type": { - "name": "document_type", - "type": "document_type", - "typeSchema": "public", - "primaryKey": false, - "notNull": true - }, - "document_location": { - "name": "document_location", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "uploaded_at": { - "name": "uploaded_at", - "type": "timestamp (6) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "scenario_id": { - "name": "scenario_id", - "type": "bigint", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "energy_assessment_documents_energy_assessment_id_energy_assessments_id_fk": { - "name": "energy_assessment_documents_energy_assessment_id_energy_assessments_id_fk", - "tableFrom": "energy_assessment_documents", - "tableTo": "energy_assessments", - "columnsFrom": [ - "energy_assessment_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "energy_assessment_documents_scenario_id_energy_assessment_scenarios_id_fk": { - "name": "energy_assessment_documents_scenario_id_energy_assessment_scenarios_id_fk", - "tableFrom": "energy_assessment_documents", - "tableTo": "energy_assessment_scenarios", - "columnsFrom": [ - "scenario_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.energy_assessment_scenarios": { - "name": "energy_assessment_scenarios", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "scenario_name": { - "name": "scenario_name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "energy_assessment_id": { - "name": "energy_assessment_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "energy_assessment_scenarios_energy_assessment_id_energy_assessments_id_fk": { - "name": "energy_assessment_scenarios_energy_assessment_id_energy_assessments_id_fk", - "tableFrom": "energy_assessment_scenarios", - "tableTo": "energy_assessments", - "columnsFrom": [ - "energy_assessment_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.funding_package": { - "name": "funding_package", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "plan_id": { - "name": "plan_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "scheme": { - "name": "scheme", - "type": "scheme", - "typeSchema": "public", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "project_funding": { - "name": "project_funding", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "total_uplift": { - "name": "total_uplift", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "full_project_score": { - "name": "full_project_score", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "partial_project_score": { - "name": "partial_project_score", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "uplift_project_score": { - "name": "uplift_project_score", - "type": "real", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "funding_package_plan_id_plan_id_fk": { - "name": "funding_package_plan_id_plan_id_fk", - "tableFrom": "funding_package", - "tableTo": "plan", - "columnsFrom": [ - "plan_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.funding_package_measures": { - "name": "funding_package_measures", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "funding_package_id": { - "name": "funding_package_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "measure": { - "name": "measure", - "type": "type", - "typeSchema": "public", - "primaryKey": false, - "notNull": true - }, - "material_id": { - "name": "material_id", - "type": "bigint", - "primaryKey": false, - "notNull": false - }, - "innovation_uplift": { - "name": "innovation_uplift", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "partial_project_score": { - "name": "partial_project_score", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "uplift_project_score": { - "name": "uplift_project_score", - "type": "real", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "funding_package_measures_funding_package_id_funding_package_id_fk": { - "name": "funding_package_measures_funding_package_id_funding_package_id_fk", - "tableFrom": "funding_package_measures", - "tableTo": "funding_package", - "columnsFrom": [ - "funding_package_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "funding_package_measures_material_id_material_id_fk": { - "name": "funding_package_measures_material_id_material_id_fk", - "tableFrom": "funding_package_measures", - "tableTo": "material", - "columnsFrom": [ - "material_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.material": { - "name": "material", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "type": { - "name": "type", - "type": "type", - "typeSchema": "public", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "depth": { - "name": "depth", - "type": "json", - "primaryKey": false, - "notNull": false - }, - "depth_unit": { - "name": "depth_unit", - "type": "depth_unit", - "typeSchema": "public", - "primaryKey": false, - "notNull": false - }, - "cost_unit": { - "name": "cost_unit", - "type": "cost_unit", - "typeSchema": "public", - "primaryKey": false, - "notNull": false - }, - "r_value_per_mm": { - "name": "r_value_per_mm", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "r_value_unit": { - "name": "r_value_unit", - "type": "r_value_unit", - "typeSchema": "public", - "primaryKey": false, - "notNull": false - }, - "thermal_conductivity": { - "name": "thermal_conductivity", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "thermal_conductivity_unit": { - "name": "thermal_conductivity_unit", - "type": "thermal_conductivity_unit", - "typeSchema": "public", - "primaryKey": false, - "notNull": false - }, - "link": { - "name": "link", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "is_active": { - "name": "is_active", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": true - }, - "prime_material_cost": { - "name": "prime_material_cost", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "material_cost": { - "name": "material_cost", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "labour_cost": { - "name": "labour_cost", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "labour_hours_per_unit": { - "name": "labour_hours_per_unit", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "plant_cost": { - "name": "plant_cost", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "total_cost": { - "name": "total_cost", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "cost": { - "name": "cost", - "type": "json", - "primaryKey": false, - "notNull": false - }, - "notes": { - "name": "notes", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "is_installer_quote": { - "name": "is_installer_quote", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "innovation_rate": { - "name": "innovation_rate", - "type": "real", - "primaryKey": false, - "notNull": false, - "default": 0 - }, - "size": { - "name": "size", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "size_unit": { - "name": "size_unit", - "type": "size_unit", - "typeSchema": "public", - "primaryKey": false, - "notNull": false - }, - "includes_scaffolding": { - "name": "includes_scaffolding", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "includes_battery": { - "name": "includes_battery", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "battery_size": { - "name": "battery_size", - "type": "real", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.portfolio": { - "name": "portfolio", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "budget": { - "name": "budget", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "status": { - "name": "status", - "type": "status", - "typeSchema": "public", - "primaryKey": false, - "notNull": true - }, - "goal": { - "name": "goal", - "type": "goal", - "typeSchema": "public", - "primaryKey": false, - "notNull": true - }, - "cost": { - "name": "cost", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "number_of_properties": { - "name": "number_of_properties", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "co2_equivalent_savings": { - "name": "co2_equivalent_savings", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "energy_savings": { - "name": "energy_savings", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "energy_cost_savings": { - "name": "energy_cost_savings", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "property_valuation_increase": { - "name": "property_valuation_increase", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "rental_yield_increase": { - "name": "rental_yield_increase", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "total_work_hours": { - "name": "total_work_hours", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "labour_days": { - "name": "labour_days", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp (6) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp (6) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "epc_breakdown_pre_retrofit": { - "name": "epc_breakdown_pre_retrofit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "epc_breakdown_post_retrofit": { - "name": "epc_breakdown_post_retrofit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "n_units_to_retrofit": { - "name": "n_units_to_retrofit", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "co2_per_unit_pre_retrofit": { - "name": "co2_per_unit_pre_retrofit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "co2_per_unit_post_retrofit": { - "name": "co2_per_unit_post_retrofit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "energy_bill_per_unit_pre_retrofit": { - "name": "energy_bill_per_unit_pre_retrofit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "energy_bill_per_unit_post_retrofit": { - "name": "energy_bill_per_unit_post_retrofit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "energy_consumption_per_unit_pre_retrofit": { - "name": "energy_consumption_per_unit_pre_retrofit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "energy_consumption_per_unit_post_retrofit": { - "name": "energy_consumption_per_unit_post_retrofit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "valuation_improvement_per_unit": { - "name": "valuation_improvement_per_unit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cost_per_unit": { - "name": "cost_per_unit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cost_per_co2_saved": { - "name": "cost_per_co2_saved", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cost_per_sap_point": { - "name": "cost_per_sap_point", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "valuation_return_on_investment": { - "name": "valuation_return_on_investment", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.portfolioUsers": { - "name": "portfolioUsers", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "portfolio_id": { - "name": "portfolio_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "role": { - "name": "role", - "type": "role", - "typeSchema": "public", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp (6) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp (6) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "portfolioUsers_user_id_user_id_fk": { - "name": "portfolioUsers_user_id_user_id_fk", - "tableFrom": "portfolioUsers", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "portfolioUsers_portfolio_id_portfolio_id_fk": { - "name": "portfolioUsers_portfolio_id_portfolio_id_fk", - "tableFrom": "portfolioUsers", - "tableTo": "portfolio", - "columnsFrom": [ - "portfolio_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.non_intrusive_survey": { - "name": "non_intrusive_survey", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "uprn": { - "name": "uprn", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "survey_date": { - "name": "survey_date", - "type": "timestamp", - "primaryKey": false, - "notNull": true - }, - "surveyor": { - "name": "surveyor", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.non_intrusive_survey_notes": { - "name": "non_intrusive_survey_notes", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "survey_id": { - "name": "survey_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "title": { - "name": "title", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "note": { - "name": "note", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "non_intrusive_survey_notes_survey_id_non_intrusive_survey_id_fk": { - "name": "non_intrusive_survey_notes_survey_id_non_intrusive_survey_id_fk", - "tableFrom": "non_intrusive_survey_notes", - "tableTo": "non_intrusive_survey", - "columnsFrom": [ - "survey_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.property": { - "name": "property", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "portfolio_id": { - "name": "portfolio_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "creation_status": { - "name": "creation_status", - "type": "creation_status", - "typeSchema": "public", - "primaryKey": false, - "notNull": true - }, - "uprn": { - "name": "uprn", - "type": "bigint", - "primaryKey": false, - "notNull": false - }, - "building_reference_number": { - "name": "building_reference_number", - "type": "bigint", - "primaryKey": false, - "notNull": false - }, - "status": { - "name": "status", - "type": "status", - "typeSchema": "public", - "primaryKey": false, - "notNull": false - }, - "address": { - "name": "address", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "postcode": { - "name": "postcode", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "has_pre_condition_report": { - "name": "has_pre_condition_report", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "has_recommendations": { - "name": "has_recommendations", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "property_type": { - "name": "property_type", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "built_form": { - "name": "built_form", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "local_authority": { - "name": "local_authority", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "constituency": { - "name": "constituency", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "number_of_rooms": { - "name": "number_of_rooms", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "year_built": { - "name": "year_built", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "tenure": { - "name": "tenure", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "current_epc_rating": { - "name": "current_epc_rating", - "type": "epc", - "typeSchema": "public", - "primaryKey": false, - "notNull": false - }, - "current_sap_points": { - "name": "current_sap_points", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "current_valuation": { - "name": "current_valuation", - "type": "real", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "property_portfolio_id_portfolio_id_fk": { - "name": "property_portfolio_id_portfolio_id_fk", - "tableFrom": "property", - "tableTo": "portfolio", - "columnsFrom": [ - "portfolio_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.property_details_epc": { - "name": "property_details_epc", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "property_id": { - "name": "property_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "portfolio_id": { - "name": "portfolio_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "full_address": { - "name": "full_address", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "total_floor_area": { - "name": "total_floor_area", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "walls": { - "name": "walls", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "walls_rating": { - "name": "walls_rating", - "type": "smallint", - "primaryKey": false, - "notNull": false - }, - "roof": { - "name": "roof", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "roof_rating": { - "name": "roof_rating", - "type": "smallint", - "primaryKey": false, - "notNull": false - }, - "floor": { - "name": "floor", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "floor_rating": { - "name": "floor_rating", - "type": "smallint", - "primaryKey": false, - "notNull": false - }, - "windows": { - "name": "windows", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "windows_rating": { - "name": "windows_rating", - "type": "smallint", - "primaryKey": false, - "notNull": false - }, - "heating": { - "name": "heating", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "heating_rating": { - "name": "heating_rating", - "type": "smallint", - "primaryKey": false, - "notNull": false - }, - "heating_controls": { - "name": "heating_controls", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "heating_controls_rating": { - "name": "heating_controls_rating", - "type": "smallint", - "primaryKey": false, - "notNull": false - }, - "hot_water": { - "name": "hot_water", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "hot_water_rating": { - "name": "hot_water_rating", - "type": "smallint", - "primaryKey": false, - "notNull": false - }, - "lighting": { - "name": "lighting", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "lighting_rating": { - "name": "lighting_rating", - "type": "smallint", - "primaryKey": false, - "notNull": false - }, - "mainfuel": { - "name": "mainfuel", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "ventilation": { - "name": "ventilation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "solar_pv": { - "name": "solar_pv", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "solar_hot_water": { - "name": "solar_hot_water", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "wind_turbine": { - "name": "wind_turbine", - "type": "smallint", - "primaryKey": false, - "notNull": false - }, - "floor_height": { - "name": "floor_height", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "number_heated_rooms": { - "name": "number_heated_rooms", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "heat_loss_corridor": { - "name": "heat_loss_corridor", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "unheated_corridor_length": { - "name": "unheated_corridor_length", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "number_of_open_fireplaces": { - "name": "number_of_open_fireplaces", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "number_of_extensions": { - "name": "number_of_extensions", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "number_of_storeys": { - "name": "number_of_storeys", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "mains_gas": { - "name": "mains_gas", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "energy_tariff": { - "name": "energy_tariff", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "primary_energy_consumption": { - "name": "primary_energy_consumption", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "co2_emissions": { - "name": "co2_emissions", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "current_energy_demand": { - "name": "current_energy_demand", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "current_energy_demand_heating_hotwater": { - "name": "current_energy_demand_heating_hotwater", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "estimated": { - "name": "estimated", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "heating_cost_current": { - "name": "heating_cost_current", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "hot_water_cost_current": { - "name": "hot_water_cost_current", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "lighting_cost_current": { - "name": "lighting_cost_current", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "appliances_cost_current": { - "name": "appliances_cost_current", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "gas_standing_charge": { - "name": "gas_standing_charge", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "electricity_standing_charge": { - "name": "electricity_standing_charge", - "type": "real", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "property_details_epc_property_id_property_id_fk": { - "name": "property_details_epc_property_id_property_id_fk", - "tableFrom": "property_details_epc", - "tableTo": "property", - "columnsFrom": [ - "property_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "property_details_epc_portfolio_id_portfolio_id_fk": { - "name": "property_details_epc_portfolio_id_portfolio_id_fk", - "tableFrom": "property_details_epc", - "tableTo": "portfolio", - "columnsFrom": [ - "portfolio_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.property_details_meter": { - "name": "property_details_meter", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "uprn": { - "name": "uprn", - "type": "bigint", - "primaryKey": false, - "notNull": false - }, - "energy_supplier": { - "name": "energy_supplier", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "gas_supplier": { - "name": "gas_supplier", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "meter_reading_total": { - "name": "meter_reading_total", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "meter_reading_electricity": { - "name": "meter_reading_electricity", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "meter_reading_gas": { - "name": "meter_reading_gas", - "type": "real", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.property_details_spatial": { - "name": "property_details_spatial", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "uprn": { - "name": "uprn", - "type": "bigint", - "primaryKey": false, - "notNull": false - }, - "x_coordinate": { - "name": "x_coordinate", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "y_coordinate": { - "name": "y_coordinate", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "latitude": { - "name": "latitude", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "longitude": { - "name": "longitude", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "conservation_status": { - "name": "conservation_status", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "is_listed_building": { - "name": "is_listed_building", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "is_heritage_building": { - "name": "is_heritage_building", - "type": "boolean", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.property_targets": { - "name": "property_targets", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "property_id": { - "name": "property_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "portfolio_id": { - "name": "portfolio_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "epc": { - "name": "epc", - "type": "epc", - "typeSchema": "public", - "primaryKey": false, - "notNull": false - }, - "heat_demand": { - "name": "heat_demand", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "property_targets_property_id_property_id_fk": { - "name": "property_targets_property_id_property_id_fk", - "tableFrom": "property_targets", - "tableTo": "property", - "columnsFrom": [ - "property_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "property_targets_portfolio_id_portfolio_id_fk": { - "name": "property_targets_portfolio_id_portfolio_id_fk", - "tableFrom": "property_targets", - "tableTo": "portfolio", - "columnsFrom": [ - "portfolio_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.plan": { - "name": "plan", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "portfolio_id": { - "name": "portfolio_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "property_id": { - "name": "property_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "scenario_id": { - "name": "scenario_id", - "type": "bigint", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "is_default": { - "name": "is_default", - "type": "boolean", - "primaryKey": false, - "notNull": true - }, - "valuation_increase_lower_bound": { - "name": "valuation_increase_lower_bound", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "valuation_increase_upper_bound": { - "name": "valuation_increase_upper_bound", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "valuation_increase_average": { - "name": "valuation_increase_average", - "type": "real", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "plan_portfolio_id_portfolio_id_fk": { - "name": "plan_portfolio_id_portfolio_id_fk", - "tableFrom": "plan", - "tableTo": "portfolio", - "columnsFrom": [ - "portfolio_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "plan_property_id_property_id_fk": { - "name": "plan_property_id_property_id_fk", - "tableFrom": "plan", - "tableTo": "property", - "columnsFrom": [ - "property_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "plan_scenario_id_scenario_id_fk": { - "name": "plan_scenario_id_scenario_id_fk", - "tableFrom": "plan", - "tableTo": "scenario", - "columnsFrom": [ - "scenario_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.plan_recommendations": { - "name": "plan_recommendations", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "plan_id": { - "name": "plan_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "recommendation_id": { - "name": "recommendation_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "plan_recommendations_plan_id_plan_id_fk": { - "name": "plan_recommendations_plan_id_plan_id_fk", - "tableFrom": "plan_recommendations", - "tableTo": "plan", - "columnsFrom": [ - "plan_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "plan_recommendations_recommendation_id_recommendation_id_fk": { - "name": "plan_recommendations_recommendation_id_recommendation_id_fk", - "tableFrom": "plan_recommendations", - "tableTo": "recommendation", - "columnsFrom": [ - "recommendation_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.recommendation": { - "name": "recommendation", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "property_id": { - "name": "property_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "measure_type": { - "name": "measure_type", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "estimated_cost": { - "name": "estimated_cost", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "contingency_cost": { - "name": "contingency_cost", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "default": { - "name": "default", - "type": "boolean", - "primaryKey": false, - "notNull": true - }, - "starting_u_value": { - "name": "starting_u_value", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "new_u_value": { - "name": "new_u_value", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "sap_points": { - "name": "sap_points", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "heat_demand": { - "name": "heat_demand", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "kwh_savings": { - "name": "kwh_savings", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "co2_equivalent_savings": { - "name": "co2_equivalent_savings", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "energy_savings": { - "name": "energy_savings", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "energy_cost_savings": { - "name": "energy_cost_savings", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "property_valuation_increase": { - "name": "property_valuation_increase", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "rental_yield_increase": { - "name": "rental_yield_increase", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "total_work_hours": { - "name": "total_work_hours", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "labour_days": { - "name": "labour_days", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "already_installed": { - "name": "already_installed", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - } - }, - "indexes": {}, - "foreignKeys": { - "recommendation_property_id_property_id_fk": { - "name": "recommendation_property_id_property_id_fk", - "tableFrom": "recommendation", - "tableTo": "property", - "columnsFrom": [ - "property_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.recommendation_materials": { - "name": "recommendation_materials", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "recommendation_id": { - "name": "recommendation_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "material_id": { - "name": "material_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "depth": { - "name": "depth", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "quantity": { - "name": "quantity", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "quantity_unit": { - "name": "quantity_unit", - "type": "unit_quantity", - "typeSchema": "public", - "primaryKey": false, - "notNull": false - }, - "estimated_cost": { - "name": "estimated_cost", - "type": "real", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "recommendation_materials_recommendation_id_recommendation_id_fk": { - "name": "recommendation_materials_recommendation_id_recommendation_id_fk", - "tableFrom": "recommendation_materials", - "tableTo": "recommendation", - "columnsFrom": [ - "recommendation_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "recommendation_materials_material_id_material_id_fk": { - "name": "recommendation_materials_material_id_material_id_fk", - "tableFrom": "recommendation_materials", - "tableTo": "material", - "columnsFrom": [ - "material_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.scenario": { - "name": "scenario", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "budget": { - "name": "budget", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "portfolio_id": { - "name": "portfolio_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "housing_type": { - "name": "housing_type", - "type": "housing_type", - "typeSchema": "public", - "primaryKey": false, - "notNull": true - }, - "goal": { - "name": "goal", - "type": "goal", - "typeSchema": "public", - "primaryKey": false, - "notNull": true - }, - "goal_value": { - "name": "goal_value", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "ashp_cop": { - "name": "ashp_cop", - "type": "real", - "primaryKey": false, - "notNull": false, - "default": 2.8 - }, - "trigger_file_path": { - "name": "trigger_file_path", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "already_installed_file_path": { - "name": "already_installed_file_path", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "patches_file_path": { - "name": "patches_file_path", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "non_invasive_recommendations_file_path": { - "name": "non_invasive_recommendations_file_path", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "exclusions": { - "name": "exclusions", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "multi_plan": { - "name": "multi_plan", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "is_default": { - "name": "is_default", - "type": "boolean", - "primaryKey": false, - "notNull": true - }, - "cost": { - "name": "cost", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "contingency": { - "name": "contingency", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "funding": { - "name": "funding", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "total_work_hours": { - "name": "total_work_hours", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "energy_savings": { - "name": "energy_savings", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "co2_equivalent_savings": { - "name": "co2_equivalent_savings", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "energy_cost_savings": { - "name": "energy_cost_savings", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "property_valuation_increase": { - "name": "property_valuation_increase", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "labour_days": { - "name": "labour_days", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "epc_breakdown_pre_retrofit": { - "name": "epc_breakdown_pre_retrofit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "epc_breakdown_post_retrofit": { - "name": "epc_breakdown_post_retrofit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "number_of_properties": { - "name": "number_of_properties", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "n_units_to_retrofit": { - "name": "n_units_to_retrofit", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "co2_per_unit_pre_retrofit": { - "name": "co2_per_unit_pre_retrofit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "co2_per_unit_post_retrofit": { - "name": "co2_per_unit_post_retrofit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "energy_bill_per_unit_pre_retrofit": { - "name": "energy_bill_per_unit_pre_retrofit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "energy_bill_per_unit_post_retrofit": { - "name": "energy_bill_per_unit_post_retrofit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "energy_consumption_per_unit_pre_retrofit": { - "name": "energy_consumption_per_unit_pre_retrofit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "energy_consumption_per_unit_post_retrofit": { - "name": "energy_consumption_per_unit_post_retrofit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "valuation_improvement_per_unit": { - "name": "valuation_improvement_per_unit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cost_per_unit": { - "name": "cost_per_unit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cost_per_co2_saved": { - "name": "cost_per_co2_saved", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cost_per_sap_point": { - "name": "cost_per_sap_point", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "valuation_return_on_investment": { - "name": "valuation_return_on_investment", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "scenario_portfolio_id_portfolio_id_fk": { - "name": "scenario_portfolio_id_portfolio_id_fk", - "tableFrom": "scenario", - "tableTo": "portfolio", - "columnsFrom": [ - "portfolio_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.solar": { - "name": "solar", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "longitude": { - "name": "longitude", - "type": "real", - "primaryKey": false, - "notNull": true - }, - "latitude": { - "name": "latitude", - "type": "real", - "primaryKey": false, - "notNull": true - }, - "uprn": { - "name": "uprn", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp (6) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp (6) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "google_api_response": { - "name": "google_api_response", - "type": "jsonb", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.solar_scenario": { - "name": "solar_scenario", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "solar_id": { - "name": "solar_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "scenario_type": { - "name": "scenario_type", - "type": "scenario_type", - "typeSchema": "public", - "primaryKey": false, - "notNull": true - }, - "number_panels": { - "name": "number_panels", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "array_kwhp": { - "name": "array_kwhp", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "lifetime_dc_kwh": { - "name": "lifetime_dc_kwh", - "type": "real", - "primaryKey": false, - "notNull": true - }, - "yearly_dc_kwh": { - "name": "yearly_dc_kwh", - "type": "real", - "primaryKey": false, - "notNull": true - }, - "lifetime_ac_kwh": { - "name": "lifetime_ac_kwh", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "yearly_ac_kwh": { - "name": "yearly_ac_kwh", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "cost": { - "name": "cost", - "type": "real", - "primaryKey": false, - "notNull": true - }, - "expected_payback_years": { - "name": "expected_payback_years", - "type": "real", - "primaryKey": false, - "notNull": false - }, - "panelled_roof_area": { - "name": "panelled_roof_area", - "type": "real", - "primaryKey": false, - "notNull": true - }, - "is_default": { - "name": "is_default", - "type": "boolean", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "solar_scenario_solar_id_solar_id_fk": { - "name": "solar_scenario_solar_id_solar_id_fk", - "tableFrom": "solar_scenario", - "tableTo": "solar", - "columnsFrom": [ - "solar_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.account": { - "name": "account", - "schema": "", - "columns": { - "userId": { - "name": "userId", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "provider": { - "name": "provider", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "providerAccountId": { - "name": "providerAccountId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "refresh_token": { - "name": "refresh_token", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "access_token": { - "name": "access_token", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "expires_at": { - "name": "expires_at", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "token_type": { - "name": "token_type", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "scope": { - "name": "scope", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "id_token": { - "name": "id_token", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "session_state": { - "name": "session_state", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "account_userId_user_id_fk": { - "name": "account_userId_user_id_fk", - "tableFrom": "account", - "tableTo": "user", - "columnsFrom": [ - "userId" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "account_provider_providerAccountId_pk": { - "name": "account_provider_providerAccountId_pk", - "columns": [ - "provider", - "providerAccountId" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.session": { - "name": "session", - "schema": "", - "columns": { - "sessionToken": { - "name": "sessionToken", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "userId": { - "name": "userId", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "expires": { - "name": "expires", - "type": "timestamp", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "session_userId_user_id_fk": { - "name": "session_userId_user_id_fk", - "tableFrom": "session", - "tableTo": "user", - "columnsFrom": [ - "userId" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user": { - "name": "user", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "firstName": { - "name": "firstName", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "emailVerified": { - "name": "emailVerified", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "oauth_id": { - "name": "oauth_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "oauth_provider": { - "name": "oauth_provider", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "image": { - "name": "image", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "onboarded": { - "name": "onboarded", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "last_login": { - "name": "last_login", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp (6) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp (6) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "user_email_unique": { - "name": "user_email_unique", - "nullsNotDistinct": false, - "columns": [ - "email" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user_profiles": { - "name": "user_profiles", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "bigserial", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "user_type": { - "name": "user_type", - "type": "user_profiles_user_type", - "typeSchema": "public", - "primaryKey": false, - "notNull": true - }, - "property_count": { - "name": "property_count", - "type": "user_profiles_property_count", - "typeSchema": "public", - "primaryKey": false, - "notNull": false - }, - "goals": { - "name": "goals", - "type": "json", - "primaryKey": false, - "notNull": false - }, - "referral_source": { - "name": "referral_source", - "type": "user_profiles_referral_source", - "typeSchema": "public", - "primaryKey": false, - "notNull": false - }, - "nrla_membership_id": { - "name": "nrla_membership_id", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "accepted_privacy": { - "name": "accepted_privacy", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "accepted_privacy_at": { - "name": "accepted_privacy_at", - "type": "timestamp (6) with time zone", - "primaryKey": false, - "notNull": false - }, - "marketing_opt_in": { - "name": "marketing_opt_in", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "marketing_opt_in_at": { - "name": "marketing_opt_in_at", - "type": "timestamp (6) with time zone", - "primaryKey": false, - "notNull": false - }, - "first_name": { - "name": "first_name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "last_name": { - "name": "last_name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp (6) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp (6) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "user_profiles_user_id_user_id_fk": { - "name": "user_profiles_user_id_user_id_fk", - "tableFrom": "user_profiles", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.verificationToken": { - "name": "verificationToken", - "schema": "", - "columns": { - "identifier": { - "name": "identifier", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "token": { - "name": "token", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "expires": { - "name": "expires", - "type": "timestamp", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "verificationToken_identifier_token_pk": { - "name": "verificationToken_identifier_token_pk", - "columns": [ - "identifier", - "token" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - } - }, - "enums": { - "public.document_type": { - "name": "document_type", - "schema": "public", - "values": [ - "EPR", - "Condition Report", - "Evidence Report", - "Summary Information", - "Floor Plan", - "Scenario Draft EPC", - "Scenario Site Notes" - ] - }, - "public.scheme": { - "name": "scheme", - "schema": "public", - "values": [ - "eco4", - "gbis", - "whlg", - "none" - ] - }, - "public.cost_unit": { - "name": "cost_unit", - "schema": "public", - "values": [ - "gbp_sq_meter", - "gbp_per_unit", - "gbp_per_m2", - "gbp_per_m" - ] - }, - "public.depth_unit": { - "name": "depth_unit", - "schema": "public", - "values": [ - "mm" - ] - }, - "public.type": { - "name": "type", - "schema": "public", - "values": [ - "suspended_floor_insulation", - "solid_floor_insulation", - "external_wall_insulation", - "internal_wall_insulation", - "cavity_wall_insulation", - "mechanical_ventilation", - "loft_insulation", - "exposed_floor_insulation", - "flat_roof_insulation", - "room_roof_insulation", - "cavity_wall_extraction", - "iwi_wall_demolition", - "iwi_vapour_barrier", - "iwi_redecoration", - "suspended_floor_demolition", - "suspended_floor_redecoration", - "suspended_floor_vapour_barrier", - "solid_floor_demolition", - "solid_floor_preparation", - "solid_floor_vapour_barrier", - "solid_floor_redecoration", - "ewi_wall_demolition", - "ewi_wall_preparation", - "ewi_wall_redecoration", - "low_energy_lighting_installation", - "flat_roof_preparation", - "flat_roof_vapour_barrier", - "flat_roof_waterproofing", - "windows_glazing", - "trickle_vent", - "door_undercut", - "solar_pv", - "solar_battery", - "scaffolding", - "high_heat_retention_storage_heaters", - "air_source_heat_pump", - "roomstat_programmer_trvs", - "time_temperature_zone_control", - "sealing_fireplace" - ] - }, - "public.r_value_unit": { - "name": "r_value_unit", - "schema": "public", - "values": [ - "square_meter_kelvin_per_watt" - ] - }, - "public.size_unit": { - "name": "size_unit", - "schema": "public", - "values": [ - "kWp", - "kW", - "watt", - "storey" - ] - }, - "public.thermal_conductivity_unit": { - "name": "thermal_conductivity_unit", - "schema": "public", - "values": [ - "watt_per_meter_kelvin" - ] - }, - "public.goal": { - "name": "goal", - "schema": "public", - "values": [ - "Valuation Improvement", - "Increasing EPC", - "Reducing CO2 emissions", - "Energy Savings", - "None" - ] - }, - "public.role": { - "name": "role", - "schema": "public", - "values": [ - "creator", - "admin", - "read", - "write" - ] - }, - "public.status": { - "name": "status", - "schema": "public", - "values": [ - "scoping", - "survey", - "assessment", - "tendering", - "project underway", - "completion; status: on track", - "completion; status: delayed", - "completion; status: at risk", - "completion; status: completed", - "needs review" - ] - }, - "public.epc": { - "name": "epc", - "schema": "public", - "values": [ - "A", - "B", - "C", - "D", - "E", - "F", - "G" - ] - }, - "public.creation_status": { - "name": "creation_status", - "schema": "public", - "values": [ - "LOADING", - "READY", - "ERROR" - ] - }, - "public.housing_type": { - "name": "housing_type", - "schema": "public", - "values": [ - "Private", - "Social" - ] - }, - "public.unit_quantity": { - "name": "unit_quantity", - "schema": "public", - "values": [ - "m2", - "part", - "kwp" - ] - }, - "public.scenario_type": { - "name": "scenario_type", - "schema": "public", - "values": [ - "unit", - "building" - ] - }, - "public.user_profiles_property_count": { - "name": "user_profiles_property_count", - "schema": "public", - "values": [ - "1", - "2–5", - "6–20", - "21+", - "1–50", - "51–100", - "101–300", - "301–1000", - "1000+" - ] - }, - "public.user_profiles_referral_source": { - "name": "user_profiles_referral_source", - "schema": "public", - "values": [ - "search", - "social_media", - "NRLA", - "partner", - "word_of_mouth", - "other" - ] - }, - "public.user_profiles_user_type": { - "name": "user_profiles_user_type", - "schema": "public", - "values": [ - "private_landlord", - "private_tenant", - "social_landlord", - "social_tenant", - "homeowner", - "other" - ] - } - }, - "schemas": {}, - "sequences": {}, - "roles": {}, - "policies": {}, - "views": {}, - "_meta": { - "columns": {}, - "schemas": {}, - "tables": {} - } -} \ No newline at end of file diff --git a/src/app/db/migrations/meta/_journal.json b/src/app/db/migrations/meta/_journal.json index fda2a5f..22a0dec 100644 --- a/src/app/db/migrations/meta/_journal.json +++ b/src/app/db/migrations/meta/_journal.json @@ -841,13 +841,6 @@ "when": 1760711090309, "tag": "0119_marvelous_blur", "breakpoints": true - }, - { - "idx": 120, - "version": "7", - "when": 1761078881645, - "tag": "0120_watery_captain_america", - "breakpoints": true } ] -} \ No newline at end of file +} From 1e5ccac3460947c17cc8142fc87e52435254193c Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Thu, 23 Oct 2025 12:46:00 +0000 Subject: [PATCH 11/15] ordnance survey working --- .../postcode/[postcode]/addresses/route.ts | 16 +- .../db/migrations/0121_chunky_tony_stark.sql | 7 + src/app/db/migrations/meta/0121_snapshot.json | 3875 +++++++++++++++++ src/app/db/migrations/meta/_journal.json | 9 +- .../remote-assessment/AddressSearch.tsx | 29 +- .../RemoteAssessmentClient.tsx | 21 +- .../remote-assessment/ScenarioSetup.tsx | 6 +- .../useCreateRemoteAssessment.tsx | 7 - 8 files changed, 3923 insertions(+), 47 deletions(-) create mode 100644 src/app/db/migrations/0121_chunky_tony_stark.sql create mode 100644 src/app/db/migrations/meta/0121_snapshot.json diff --git a/src/app/api/postcode/[postcode]/addresses/route.ts b/src/app/api/postcode/[postcode]/addresses/route.ts index df1fcf5..57756b4 100644 --- a/src/app/api/postcode/[postcode]/addresses/route.ts +++ b/src/app/api/postcode/[postcode]/addresses/route.ts @@ -5,11 +5,6 @@ import { eq } from "drizzle-orm"; import { lookupOsPlaces } from "@/app/api/postcode/LookupOsPlaces"; import { mapOsPlacesToFlat } from "@/app/api/postcode/OsPlacesToFlat"; -// Utility to normalize the postcode format -function normalizePostcode(postcode: string) { - return postcode.toUpperCase().replace(/\s+/g, ""); -} - export async function GET( _req: Request, { params }: { params: { postcode: string } } @@ -22,17 +17,16 @@ export async function GET( ); } - const normalized = normalizePostcode(postcode); - try { // Step 1: check cache const cached = await db .select() .from(postcodeSearch) - .where(eq(postcodeSearch.postcode, normalized)) + .where(eq(postcodeSearch.postcode, postcode)) .limit(1); if (cached.length > 0) { + console.log("Using cached OS Places data for postcode:", postcode); const record = cached[0]; const addresses = mapOsPlacesToFlat(record.resultData?.results); return NextResponse.json({ @@ -44,7 +38,7 @@ export async function GET( } // Step 2: if no cache, query OS Places API - const result = await lookupOsPlaces(normalized); + const result = await lookupOsPlaces(postcode); if (result.error || result.status !== 200 || !result.data) { return NextResponse.json( { @@ -55,14 +49,12 @@ export async function GET( ); } - console.log("Fetched OS Places data:", result); - // Step 3: flatten and cache the result const addresses = mapOsPlacesToFlat(result.results); const total = result.data.header?.totalresults ?? addresses.length; await db.insert(postcodeSearch).values({ - postcode: normalized, + postcode: postcode, resultData: result.data, }); diff --git a/src/app/db/migrations/0121_chunky_tony_stark.sql b/src/app/db/migrations/0121_chunky_tony_stark.sql new file mode 100644 index 0000000..81d666a --- /dev/null +++ b/src/app/db/migrations/0121_chunky_tony_stark.sql @@ -0,0 +1,7 @@ +CREATE TABLE "postcode_search" ( + "id" serial PRIMARY KEY NOT NULL, + "postcode" text NOT NULL, + "result_data" jsonb NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL, + CONSTRAINT "postcode_search_postcode_unique" UNIQUE("postcode") +); diff --git a/src/app/db/migrations/meta/0121_snapshot.json b/src/app/db/migrations/meta/0121_snapshot.json new file mode 100644 index 0000000..e50230a --- /dev/null +++ b/src/app/db/migrations/meta/0121_snapshot.json @@ -0,0 +1,3875 @@ +{ + "id": "af3ae609-b69b-40db-8997-0a376f597f88", + "prevId": "53a7efd8-4539-4bbe-80a8-afeeea00c07b", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.postcode_search": { + "name": "postcode_search", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "result_data": { + "name": "result_data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "postcode_search_postcode_unique": { + "name": "postcode_search_postcode_unique", + "nullsNotDistinct": false, + "columns": [ + "postcode" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_status_tracker": { + "name": "property_status_tracker", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "property_status_tracker_property_id_property_id_fk": { + "name": "property_status_tracker_property_id_property_id_fk", + "tableFrom": "property_status_tracker", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "property_status_tracker_portfolio_id_portfolio_id_fk": { + "name": "property_status_tracker_portfolio_id_portfolio_id_fk", + "tableFrom": "property_status_tracker", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.energy_assessments": { + "name": "energy_assessments", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "uprn_source": { + "name": "uprn_source", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "property_type": { + "name": "property_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "building_reference_number": { + "name": "building_reference_number", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "current_energy_efficiency": { + "name": "current_energy_efficiency", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "current_energy_rating": { + "name": "current_energy_rating", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "address1": { + "name": "address1", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "address2": { + "name": "address2", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "address3": { + "name": "address3", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "posttown": { + "name": "posttown", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "address": { + "name": "address", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "county": { + "name": "county", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "constituency": { + "name": "constituency", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "constituency_label": { + "name": "constituency_label", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "low_energy_fixed_light_count": { + "name": "low_energy_fixed_light_count", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "construction_age_band": { + "name": "construction_age_band", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mainheat_energy_eff": { + "name": "mainheat_energy_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "windows_env_eff": { + "name": "windows_env_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "lighting_energy_eff": { + "name": "lighting_energy_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "environment_impact_potential": { + "name": "environment_impact_potential", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mainheatcont_description": { + "name": "mainheatcont_description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "sheating_energy_eff": { + "name": "sheating_energy_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "local_authority": { + "name": "local_authority", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "local_authority_label": { + "name": "local_authority_label", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "fixed_lighting_outlets_count": { + "name": "fixed_lighting_outlets_count", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "energy_tariff": { + "name": "energy_tariff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mechanical_ventilation": { + "name": "mechanical_ventilation", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "solar_water_heating_flag": { + "name": "solar_water_heating_flag", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "co2_emissions_potential": { + "name": "co2_emissions_potential", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "number_heated_rooms": { + "name": "number_heated_rooms", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "floor_description": { + "name": "floor_description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "energy_consumption_potential": { + "name": "energy_consumption_potential", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "built_form": { + "name": "built_form", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "number_open_fireplaces": { + "name": "number_open_fireplaces", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "windows_description": { + "name": "windows_description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "glazed_area": { + "name": "glazed_area", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "inspection_date": { + "name": "inspection_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true + }, + "mains_gas_flag": { + "name": "mains_gas_flag", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "co2_emiss_curr_per_floor_area": { + "name": "co2_emiss_curr_per_floor_area", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "heat_loss_corridor": { + "name": "heat_loss_corridor", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "unheated_corridor_length": { + "name": "unheated_corridor_length", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "flat_storey_count": { + "name": "flat_storey_count", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "roof_energy_eff": { + "name": "roof_energy_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "total_floor_area": { + "name": "total_floor_area", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "environment_impact_current": { + "name": "environment_impact_current", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "roof_description": { + "name": "roof_description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "floor_energy_eff": { + "name": "floor_energy_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "number_habitable_rooms": { + "name": "number_habitable_rooms", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "hot_water_env_eff": { + "name": "hot_water_env_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mainheatc_energy_eff": { + "name": "mainheatc_energy_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "main_fuel": { + "name": "main_fuel", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "lighting_env_eff": { + "name": "lighting_env_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "windows_energy_eff": { + "name": "windows_energy_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "floor_env_eff": { + "name": "floor_env_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "sheating_env_eff": { + "name": "sheating_env_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "lighting_description": { + "name": "lighting_description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "roof_env_eff": { + "name": "roof_env_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "walls_energy_eff": { + "name": "walls_energy_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "photo_supply": { + "name": "photo_supply", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "lighting_cost_potential": { + "name": "lighting_cost_potential", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mainheat_env_eff": { + "name": "mainheat_env_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "multi_glaze_proportion": { + "name": "multi_glaze_proportion", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "main_heating_controls": { + "name": "main_heating_controls", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "flat_top_storey": { + "name": "flat_top_storey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secondheat_description": { + "name": "secondheat_description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "walls_env_eff": { + "name": "walls_env_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "transaction_type": { + "name": "transaction_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "extension_count": { + "name": "extension_count", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mainheatc_env_eff": { + "name": "mainheatc_env_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "lmk_key": { + "name": "lmk_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "wind_turbine_count": { + "name": "wind_turbine_count", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tenure": { + "name": "tenure", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "floor_level": { + "name": "floor_level", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "potential_energy_efficiency": { + "name": "potential_energy_efficiency", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "potential_energy_rating": { + "name": "potential_energy_rating", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "hot_water_energy_eff": { + "name": "hot_water_energy_eff", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "low_energy_lighting": { + "name": "low_energy_lighting", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "walls_description": { + "name": "walls_description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "hotwater_description": { + "name": "hotwater_description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "co2_emissions_current": { + "name": "co2_emissions_current", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "heating_cost_current": { + "name": "heating_cost_current", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "heating_cost_potential": { + "name": "heating_cost_potential", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "hot_water_cost_current": { + "name": "hot_water_cost_current", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "hot_water_cost_potential": { + "name": "hot_water_cost_potential", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "lighting_cost_current": { + "name": "lighting_cost_current", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "energy_consumption_current": { + "name": "energy_consumption_current", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "lodgement_date": { + "name": "lodgement_date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "lodgement_datetime": { + "name": "lodgement_datetime", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true + }, + "mainheat_description": { + "name": "mainheat_description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "floor_height": { + "name": "floor_height", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "glazed_type": { + "name": "glazed_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "file_location": { + "name": "file_location", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "surveyor_name": { + "name": "surveyor_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "surveyor_company": { + "name": "surveyor_company", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "space_heating_kwh": { + "name": "space_heating_kwh", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "water_heating_kwh": { + "name": "water_heating_kwh", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "number_of_doors": { + "name": "number_of_doors", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "number_of_insulated_doors": { + "name": "number_of_insulated_doors", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "number_of_floors": { + "name": "number_of_floors", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "insulation_wall_area": { + "name": "insulation_wall_area", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "heat_loss_perimeter": { + "name": "heat_loss_perimeter", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "party_wall_length": { + "name": "party_wall_length", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "perimeter": { + "name": "perimeter", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "rooms_with_bath_and_or_shower": { + "name": "rooms_with_bath_and_or_shower", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "rooms_with_mixer_shower_no_bath": { + "name": "rooms_with_mixer_shower_no_bath", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "room_with_bath_and_mixer_shower": { + "name": "room_with_bath_and_mixer_shower", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "percent_draftproofed": { + "name": "percent_draftproofed", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "has_hot_water_cylinder": { + "name": "has_hot_water_cylinder", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "cylinder_insulation_type": { + "name": "cylinder_insulation_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cylinder_insulation_thickness": { + "name": "cylinder_insulation_thickness", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cylinder_thermostat": { + "name": "cylinder_thermostat", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "main_dwelling_ground_floor_area": { + "name": "main_dwelling_ground_floor_area", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "number_of_windows": { + "name": "number_of_windows", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "windows_area": { + "name": "windows_area", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.energy_assessment_documents": { + "name": "energy_assessment_documents", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "energy_assessment_id": { + "name": "energy_assessment_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "document_type": { + "name": "document_type", + "type": "document_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "document_location": { + "name": "document_location", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "scenario_id": { + "name": "scenario_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "energy_assessment_documents_energy_assessment_id_energy_assessments_id_fk": { + "name": "energy_assessment_documents_energy_assessment_id_energy_assessments_id_fk", + "tableFrom": "energy_assessment_documents", + "tableTo": "energy_assessments", + "columnsFrom": [ + "energy_assessment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "energy_assessment_documents_scenario_id_energy_assessment_scenarios_id_fk": { + "name": "energy_assessment_documents_scenario_id_energy_assessment_scenarios_id_fk", + "tableFrom": "energy_assessment_documents", + "tableTo": "energy_assessment_scenarios", + "columnsFrom": [ + "scenario_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.energy_assessment_scenarios": { + "name": "energy_assessment_scenarios", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "scenario_name": { + "name": "scenario_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "energy_assessment_id": { + "name": "energy_assessment_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "energy_assessment_scenarios_energy_assessment_id_energy_assessments_id_fk": { + "name": "energy_assessment_scenarios_energy_assessment_id_energy_assessments_id_fk", + "tableFrom": "energy_assessment_scenarios", + "tableTo": "energy_assessments", + "columnsFrom": [ + "energy_assessment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.funding_package": { + "name": "funding_package", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "plan_id": { + "name": "plan_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "scheme": { + "name": "scheme", + "type": "scheme", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "project_funding": { + "name": "project_funding", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "total_uplift": { + "name": "total_uplift", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "full_project_score": { + "name": "full_project_score", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "partial_project_score": { + "name": "partial_project_score", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "uplift_project_score": { + "name": "uplift_project_score", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "funding_package_plan_id_plan_id_fk": { + "name": "funding_package_plan_id_plan_id_fk", + "tableFrom": "funding_package", + "tableTo": "plan", + "columnsFrom": [ + "plan_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.funding_package_measures": { + "name": "funding_package_measures", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "funding_package_id": { + "name": "funding_package_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "measure": { + "name": "measure", + "type": "type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "material_id": { + "name": "material_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "innovation_uplift": { + "name": "innovation_uplift", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "partial_project_score": { + "name": "partial_project_score", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "uplift_project_score": { + "name": "uplift_project_score", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "funding_package_measures_funding_package_id_funding_package_id_fk": { + "name": "funding_package_measures_funding_package_id_funding_package_id_fk", + "tableFrom": "funding_package_measures", + "tableTo": "funding_package", + "columnsFrom": [ + "funding_package_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "funding_package_measures_material_id_material_id_fk": { + "name": "funding_package_measures_material_id_material_id_fk", + "tableFrom": "funding_package_measures", + "tableTo": "material", + "columnsFrom": [ + "material_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.material": { + "name": "material", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "depth": { + "name": "depth", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "depth_unit": { + "name": "depth_unit", + "type": "depth_unit", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "cost_unit": { + "name": "cost_unit", + "type": "cost_unit", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "r_value_per_mm": { + "name": "r_value_per_mm", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "r_value_unit": { + "name": "r_value_unit", + "type": "r_value_unit", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "thermal_conductivity": { + "name": "thermal_conductivity", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "thermal_conductivity_unit": { + "name": "thermal_conductivity_unit", + "type": "thermal_conductivity_unit", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "link": { + "name": "link", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "prime_material_cost": { + "name": "prime_material_cost", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "material_cost": { + "name": "material_cost", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "labour_cost": { + "name": "labour_cost", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "labour_hours_per_unit": { + "name": "labour_hours_per_unit", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "plant_cost": { + "name": "plant_cost", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "total_cost": { + "name": "total_cost", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cost": { + "name": "cost", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_installer_quote": { + "name": "is_installer_quote", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "innovation_rate": { + "name": "innovation_rate", + "type": "real", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "size": { + "name": "size", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "size_unit": { + "name": "size_unit", + "type": "size_unit", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "includes_scaffolding": { + "name": "includes_scaffolding", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "includes_battery": { + "name": "includes_battery", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "battery_size": { + "name": "battery_size", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.portfolio": { + "name": "portfolio", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "budget": { + "name": "budget", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "goal": { + "name": "goal", + "type": "goal", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "cost": { + "name": "cost", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "number_of_properties": { + "name": "number_of_properties", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "co2_equivalent_savings": { + "name": "co2_equivalent_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_savings": { + "name": "energy_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_cost_savings": { + "name": "energy_cost_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "property_valuation_increase": { + "name": "property_valuation_increase", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "rental_yield_increase": { + "name": "rental_yield_increase", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "total_work_hours": { + "name": "total_work_hours", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "labour_days": { + "name": "labour_days", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "epc_breakdown_pre_retrofit": { + "name": "epc_breakdown_pre_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_breakdown_post_retrofit": { + "name": "epc_breakdown_post_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "n_units_to_retrofit": { + "name": "n_units_to_retrofit", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "co2_per_unit_pre_retrofit": { + "name": "co2_per_unit_pre_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "co2_per_unit_post_retrofit": { + "name": "co2_per_unit_post_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "energy_bill_per_unit_pre_retrofit": { + "name": "energy_bill_per_unit_pre_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "energy_bill_per_unit_post_retrofit": { + "name": "energy_bill_per_unit_post_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "energy_consumption_per_unit_pre_retrofit": { + "name": "energy_consumption_per_unit_pre_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "energy_consumption_per_unit_post_retrofit": { + "name": "energy_consumption_per_unit_post_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "valuation_improvement_per_unit": { + "name": "valuation_improvement_per_unit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cost_per_unit": { + "name": "cost_per_unit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cost_per_co2_saved": { + "name": "cost_per_co2_saved", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cost_per_sap_point": { + "name": "cost_per_sap_point", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "valuation_return_on_investment": { + "name": "valuation_return_on_investment", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.portfolioUsers": { + "name": "portfolioUsers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "portfolioUsers_user_id_user_id_fk": { + "name": "portfolioUsers_user_id_user_id_fk", + "tableFrom": "portfolioUsers", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "portfolioUsers_portfolio_id_portfolio_id_fk": { + "name": "portfolioUsers_portfolio_id_portfolio_id_fk", + "tableFrom": "portfolioUsers", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.non_intrusive_survey": { + "name": "non_intrusive_survey", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "survey_date": { + "name": "survey_date", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "surveyor": { + "name": "surveyor", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.non_intrusive_survey_notes": { + "name": "non_intrusive_survey_notes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "survey_id": { + "name": "survey_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "non_intrusive_survey_notes_survey_id_non_intrusive_survey_id_fk": { + "name": "non_intrusive_survey_notes_survey_id_non_intrusive_survey_id_fk", + "tableFrom": "non_intrusive_survey_notes", + "tableTo": "non_intrusive_survey", + "columnsFrom": [ + "survey_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property": { + "name": "property", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "creation_status": { + "name": "creation_status", + "type": "creation_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "building_reference_number": { + "name": "building_reference_number", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "status", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "address": { + "name": "address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "has_pre_condition_report": { + "name": "has_pre_condition_report", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "has_recommendations": { + "name": "has_recommendations", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "property_type": { + "name": "property_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "built_form": { + "name": "built_form", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "local_authority": { + "name": "local_authority", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "constituency": { + "name": "constituency", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "number_of_rooms": { + "name": "number_of_rooms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "year_built": { + "name": "year_built", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tenure": { + "name": "tenure", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "current_epc_rating": { + "name": "current_epc_rating", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "current_sap_points": { + "name": "current_sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "current_valuation": { + "name": "current_valuation", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "property_portfolio_id_portfolio_id_fk": { + "name": "property_portfolio_id_portfolio_id_fk", + "tableFrom": "property", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_details_epc": { + "name": "property_details_epc", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "full_address": { + "name": "full_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "total_floor_area": { + "name": "total_floor_area", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "walls": { + "name": "walls", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "walls_rating": { + "name": "walls_rating", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "roof": { + "name": "roof", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "roof_rating": { + "name": "roof_rating", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "floor": { + "name": "floor", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "floor_rating": { + "name": "floor_rating", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "windows": { + "name": "windows", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "windows_rating": { + "name": "windows_rating", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "heating": { + "name": "heating", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "heating_rating": { + "name": "heating_rating", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "heating_controls": { + "name": "heating_controls", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "heating_controls_rating": { + "name": "heating_controls_rating", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "hot_water": { + "name": "hot_water", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "hot_water_rating": { + "name": "hot_water_rating", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "lighting": { + "name": "lighting", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lighting_rating": { + "name": "lighting_rating", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "mainfuel": { + "name": "mainfuel", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ventilation": { + "name": "ventilation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "solar_pv": { + "name": "solar_pv", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "solar_hot_water": { + "name": "solar_hot_water", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "wind_turbine": { + "name": "wind_turbine", + "type": "smallint", + "primaryKey": false, + "notNull": false + }, + "floor_height": { + "name": "floor_height", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "number_heated_rooms": { + "name": "number_heated_rooms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heat_loss_corridor": { + "name": "heat_loss_corridor", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "unheated_corridor_length": { + "name": "unheated_corridor_length", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "number_of_open_fireplaces": { + "name": "number_of_open_fireplaces", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "number_of_extensions": { + "name": "number_of_extensions", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "number_of_storeys": { + "name": "number_of_storeys", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mains_gas": { + "name": "mains_gas", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "energy_tariff": { + "name": "energy_tariff", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "primary_energy_consumption": { + "name": "primary_energy_consumption", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_emissions": { + "name": "co2_emissions", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "current_energy_demand": { + "name": "current_energy_demand", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "current_energy_demand_heating_hotwater": { + "name": "current_energy_demand_heating_hotwater", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "estimated": { + "name": "estimated", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "heating_cost_current": { + "name": "heating_cost_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "hot_water_cost_current": { + "name": "hot_water_cost_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lighting_cost_current": { + "name": "lighting_cost_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "appliances_cost_current": { + "name": "appliances_cost_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "gas_standing_charge": { + "name": "gas_standing_charge", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "electricity_standing_charge": { + "name": "electricity_standing_charge", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "property_details_epc_property_id_property_id_fk": { + "name": "property_details_epc_property_id_property_id_fk", + "tableFrom": "property_details_epc", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "property_details_epc_portfolio_id_portfolio_id_fk": { + "name": "property_details_epc_portfolio_id_portfolio_id_fk", + "tableFrom": "property_details_epc", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_details_meter": { + "name": "property_details_meter", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "energy_supplier": { + "name": "energy_supplier", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gas_supplier": { + "name": "gas_supplier", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "meter_reading_total": { + "name": "meter_reading_total", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "meter_reading_electricity": { + "name": "meter_reading_electricity", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "meter_reading_gas": { + "name": "meter_reading_gas", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_details_spatial": { + "name": "property_details_spatial", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "x_coordinate": { + "name": "x_coordinate", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "y_coordinate": { + "name": "y_coordinate", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "latitude": { + "name": "latitude", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "longitude": { + "name": "longitude", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "conservation_status": { + "name": "conservation_status", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "is_listed_building": { + "name": "is_listed_building", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "is_heritage_building": { + "name": "is_heritage_building", + "type": "boolean", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_targets": { + "name": "property_targets", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "epc": { + "name": "epc", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "heat_demand": { + "name": "heat_demand", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "property_targets_property_id_property_id_fk": { + "name": "property_targets_property_id_property_id_fk", + "tableFrom": "property_targets", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "property_targets_portfolio_id_portfolio_id_fk": { + "name": "property_targets_portfolio_id_portfolio_id_fk", + "tableFrom": "property_targets", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.plan": { + "name": "plan", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "scenario_id": { + "name": "scenario_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "is_default": { + "name": "is_default", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "valuation_increase_lower_bound": { + "name": "valuation_increase_lower_bound", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "valuation_increase_upper_bound": { + "name": "valuation_increase_upper_bound", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "valuation_increase_average": { + "name": "valuation_increase_average", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "plan_portfolio_id_portfolio_id_fk": { + "name": "plan_portfolio_id_portfolio_id_fk", + "tableFrom": "plan", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "plan_property_id_property_id_fk": { + "name": "plan_property_id_property_id_fk", + "tableFrom": "plan", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "plan_scenario_id_scenario_id_fk": { + "name": "plan_scenario_id_scenario_id_fk", + "tableFrom": "plan", + "tableTo": "scenario", + "columnsFrom": [ + "scenario_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.plan_recommendations": { + "name": "plan_recommendations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "plan_id": { + "name": "plan_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "recommendation_id": { + "name": "recommendation_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "plan_recommendations_plan_id_plan_id_fk": { + "name": "plan_recommendations_plan_id_plan_id_fk", + "tableFrom": "plan_recommendations", + "tableTo": "plan", + "columnsFrom": [ + "plan_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "plan_recommendations_recommendation_id_recommendation_id_fk": { + "name": "plan_recommendations_recommendation_id_recommendation_id_fk", + "tableFrom": "plan_recommendations", + "tableTo": "recommendation", + "columnsFrom": [ + "recommendation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.recommendation": { + "name": "recommendation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "measure_type": { + "name": "measure_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "estimated_cost": { + "name": "estimated_cost", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "contingency_cost": { + "name": "contingency_cost", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "default": { + "name": "default", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "starting_u_value": { + "name": "starting_u_value", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "new_u_value": { + "name": "new_u_value", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "sap_points": { + "name": "sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "heat_demand": { + "name": "heat_demand", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "kwh_savings": { + "name": "kwh_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_equivalent_savings": { + "name": "co2_equivalent_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_savings": { + "name": "energy_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_cost_savings": { + "name": "energy_cost_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "property_valuation_increase": { + "name": "property_valuation_increase", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "rental_yield_increase": { + "name": "rental_yield_increase", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "total_work_hours": { + "name": "total_work_hours", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "labour_days": { + "name": "labour_days", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "already_installed": { + "name": "already_installed", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "recommendation_property_id_property_id_fk": { + "name": "recommendation_property_id_property_id_fk", + "tableFrom": "recommendation", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.recommendation_materials": { + "name": "recommendation_materials", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "recommendation_id": { + "name": "recommendation_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "material_id": { + "name": "material_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "depth": { + "name": "depth", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "quantity": { + "name": "quantity", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "quantity_unit": { + "name": "quantity_unit", + "type": "unit_quantity", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "estimated_cost": { + "name": "estimated_cost", + "type": "real", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "recommendation_materials_recommendation_id_recommendation_id_fk": { + "name": "recommendation_materials_recommendation_id_recommendation_id_fk", + "tableFrom": "recommendation_materials", + "tableTo": "recommendation", + "columnsFrom": [ + "recommendation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "recommendation_materials_material_id_material_id_fk": { + "name": "recommendation_materials_material_id_material_id_fk", + "tableFrom": "recommendation_materials", + "tableTo": "material", + "columnsFrom": [ + "material_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.scenario": { + "name": "scenario", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "budget": { + "name": "budget", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "housing_type": { + "name": "housing_type", + "type": "housing_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "goal": { + "name": "goal", + "type": "goal", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "goal_value": { + "name": "goal_value", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ashp_cop": { + "name": "ashp_cop", + "type": "real", + "primaryKey": false, + "notNull": false, + "default": 2.8 + }, + "trigger_file_path": { + "name": "trigger_file_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "already_installed_file_path": { + "name": "already_installed_file_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "patches_file_path": { + "name": "patches_file_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "non_invasive_recommendations_file_path": { + "name": "non_invasive_recommendations_file_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "exclusions": { + "name": "exclusions", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "multi_plan": { + "name": "multi_plan", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "is_default": { + "name": "is_default", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "cost": { + "name": "cost", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "contingency": { + "name": "contingency", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "funding": { + "name": "funding", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "total_work_hours": { + "name": "total_work_hours", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_savings": { + "name": "energy_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_equivalent_savings": { + "name": "co2_equivalent_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_cost_savings": { + "name": "energy_cost_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "property_valuation_increase": { + "name": "property_valuation_increase", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "labour_days": { + "name": "labour_days", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "epc_breakdown_pre_retrofit": { + "name": "epc_breakdown_pre_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_breakdown_post_retrofit": { + "name": "epc_breakdown_post_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "number_of_properties": { + "name": "number_of_properties", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "n_units_to_retrofit": { + "name": "n_units_to_retrofit", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "co2_per_unit_pre_retrofit": { + "name": "co2_per_unit_pre_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "co2_per_unit_post_retrofit": { + "name": "co2_per_unit_post_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "energy_bill_per_unit_pre_retrofit": { + "name": "energy_bill_per_unit_pre_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "energy_bill_per_unit_post_retrofit": { + "name": "energy_bill_per_unit_post_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "energy_consumption_per_unit_pre_retrofit": { + "name": "energy_consumption_per_unit_pre_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "energy_consumption_per_unit_post_retrofit": { + "name": "energy_consumption_per_unit_post_retrofit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "valuation_improvement_per_unit": { + "name": "valuation_improvement_per_unit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cost_per_unit": { + "name": "cost_per_unit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cost_per_co2_saved": { + "name": "cost_per_co2_saved", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cost_per_sap_point": { + "name": "cost_per_sap_point", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "valuation_return_on_investment": { + "name": "valuation_return_on_investment", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "scenario_portfolio_id_portfolio_id_fk": { + "name": "scenario_portfolio_id_portfolio_id_fk", + "tableFrom": "scenario", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.solar": { + "name": "solar", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "longitude": { + "name": "longitude", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "latitude": { + "name": "latitude", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "google_api_response": { + "name": "google_api_response", + "type": "jsonb", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.solar_scenario": { + "name": "solar_scenario", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "solar_id": { + "name": "solar_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "scenario_type": { + "name": "scenario_type", + "type": "scenario_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "number_panels": { + "name": "number_panels", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "array_kwhp": { + "name": "array_kwhp", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "lifetime_dc_kwh": { + "name": "lifetime_dc_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "yearly_dc_kwh": { + "name": "yearly_dc_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "lifetime_ac_kwh": { + "name": "lifetime_ac_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "yearly_ac_kwh": { + "name": "yearly_ac_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cost": { + "name": "cost", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "expected_payback_years": { + "name": "expected_payback_years", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "panelled_roof_area": { + "name": "panelled_roof_area", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "is_default": { + "name": "is_default", + "type": "boolean", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "solar_scenario_solar_id_solar_id_fk": { + "name": "solar_scenario_solar_id_solar_id_fk", + "tableFrom": "solar_scenario", + "tableTo": "solar", + "columnsFrom": [ + "solar_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.account": { + "name": "account", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "name": "account_provider_providerAccountId_pk", + "columns": [ + "provider", + "providerAccountId" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "firstName": { + "name": "firstName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "emailVerified": { + "name": "emailVerified", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "oauth_id": { + "name": "oauth_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "oauth_provider": { + "name": "oauth_provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "onboarded": { + "name": "onboarded", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "last_login": { + "name": "last_login", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_profiles": { + "name": "user_profiles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "user_type": { + "name": "user_type", + "type": "user_profiles_user_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "property_count": { + "name": "property_count", + "type": "user_profiles_property_count", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "goals": { + "name": "goals", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "referral_source": { + "name": "referral_source", + "type": "user_profiles_referral_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "nrla_membership_id": { + "name": "nrla_membership_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "accepted_privacy": { + "name": "accepted_privacy", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "accepted_privacy_at": { + "name": "accepted_privacy_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "marketing_opt_in": { + "name": "marketing_opt_in", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "marketing_opt_in_at": { + "name": "marketing_opt_in_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_profiles_user_id_user_id_fk": { + "name": "user_profiles_user_id_user_id_fk", + "tableFrom": "user_profiles", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verificationToken": { + "name": "verificationToken", + "schema": "", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.document_type": { + "name": "document_type", + "schema": "public", + "values": [ + "EPR", + "Condition Report", + "Evidence Report", + "Summary Information", + "Floor Plan", + "Scenario Draft EPC", + "Scenario Site Notes" + ] + }, + "public.scheme": { + "name": "scheme", + "schema": "public", + "values": [ + "eco4", + "gbis", + "whlg", + "none" + ] + }, + "public.cost_unit": { + "name": "cost_unit", + "schema": "public", + "values": [ + "gbp_sq_meter", + "gbp_per_unit", + "gbp_per_m2", + "gbp_per_m" + ] + }, + "public.depth_unit": { + "name": "depth_unit", + "schema": "public", + "values": [ + "mm" + ] + }, + "public.type": { + "name": "type", + "schema": "public", + "values": [ + "suspended_floor_insulation", + "solid_floor_insulation", + "external_wall_insulation", + "internal_wall_insulation", + "cavity_wall_insulation", + "mechanical_ventilation", + "loft_insulation", + "exposed_floor_insulation", + "flat_roof_insulation", + "room_roof_insulation", + "cavity_wall_extraction", + "iwi_wall_demolition", + "iwi_vapour_barrier", + "iwi_redecoration", + "suspended_floor_demolition", + "suspended_floor_redecoration", + "suspended_floor_vapour_barrier", + "solid_floor_demolition", + "solid_floor_preparation", + "solid_floor_vapour_barrier", + "solid_floor_redecoration", + "ewi_wall_demolition", + "ewi_wall_preparation", + "ewi_wall_redecoration", + "low_energy_lighting_installation", + "flat_roof_preparation", + "flat_roof_vapour_barrier", + "flat_roof_waterproofing", + "windows_glazing", + "trickle_vent", + "door_undercut", + "solar_pv", + "solar_battery", + "scaffolding", + "high_heat_retention_storage_heaters", + "air_source_heat_pump", + "roomstat_programmer_trvs", + "time_temperature_zone_control", + "sealing_fireplace" + ] + }, + "public.r_value_unit": { + "name": "r_value_unit", + "schema": "public", + "values": [ + "square_meter_kelvin_per_watt" + ] + }, + "public.size_unit": { + "name": "size_unit", + "schema": "public", + "values": [ + "kWp", + "kW", + "watt", + "storey" + ] + }, + "public.thermal_conductivity_unit": { + "name": "thermal_conductivity_unit", + "schema": "public", + "values": [ + "watt_per_meter_kelvin" + ] + }, + "public.goal": { + "name": "goal", + "schema": "public", + "values": [ + "Valuation Improvement", + "Increasing EPC", + "Reducing CO2 emissions", + "Energy Savings", + "None" + ] + }, + "public.role": { + "name": "role", + "schema": "public", + "values": [ + "creator", + "admin", + "read", + "write" + ] + }, + "public.status": { + "name": "status", + "schema": "public", + "values": [ + "scoping", + "survey", + "assessment", + "tendering", + "project underway", + "completion; status: on track", + "completion; status: delayed", + "completion; status: at risk", + "completion; status: completed", + "needs review" + ] + }, + "public.epc": { + "name": "epc", + "schema": "public", + "values": [ + "A", + "B", + "C", + "D", + "E", + "F", + "G" + ] + }, + "public.creation_status": { + "name": "creation_status", + "schema": "public", + "values": [ + "LOADING", + "READY", + "ERROR" + ] + }, + "public.housing_type": { + "name": "housing_type", + "schema": "public", + "values": [ + "Private", + "Social" + ] + }, + "public.unit_quantity": { + "name": "unit_quantity", + "schema": "public", + "values": [ + "m2", + "part", + "kwp" + ] + }, + "public.scenario_type": { + "name": "scenario_type", + "schema": "public", + "values": [ + "unit", + "building" + ] + }, + "public.user_profiles_property_count": { + "name": "user_profiles_property_count", + "schema": "public", + "values": [ + "1", + "2–5", + "6–20", + "21+", + "1–50", + "51–100", + "101–300", + "301–1000", + "1000+" + ] + }, + "public.user_profiles_referral_source": { + "name": "user_profiles_referral_source", + "schema": "public", + "values": [ + "search", + "social_media", + "NRLA", + "partner", + "word_of_mouth", + "other" + ] + }, + "public.user_profiles_user_type": { + "name": "user_profiles_user_type", + "schema": "public", + "values": [ + "private_landlord", + "private_tenant", + "social_landlord", + "social_tenant", + "homeowner", + "other" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/src/app/db/migrations/meta/_journal.json b/src/app/db/migrations/meta/_journal.json index ae0f99c..2b4c033 100644 --- a/src/app/db/migrations/meta/_journal.json +++ b/src/app/db/migrations/meta/_journal.json @@ -848,6 +848,13 @@ "when": 1761146299937, "tag": "0120_flashy_puck", "breakpoints": true + }, + { + "idx": 121, + "version": "7", + "when": 1761218186670, + "tag": "0121_chunky_tony_stark", + "breakpoints": true } ] -} +} \ No newline at end of file diff --git a/src/app/portfolio/[slug]/remote-assessment/AddressSearch.tsx b/src/app/portfolio/[slug]/remote-assessment/AddressSearch.tsx index 9c5bc7c..26d44ce 100644 --- a/src/app/portfolio/[slug]/remote-assessment/AddressSearch.tsx +++ b/src/app/portfolio/[slug]/remote-assessment/AddressSearch.tsx @@ -24,12 +24,14 @@ export default function AddressSearch({ onPostcodeSelect, postcode, }: { - onAddressSelect: (address: string | null) => void; + onAddressSelect: (address: AddressItem | null) => void; // ✅ Fix type onPostcodeSelect: (postcode: string) => void; postcode: string; }) { const [addresses, setAddresses] = useState([]); - const [selectedAddress, setSelectedAddress] = useState(null); + const [selectedAddress, setSelectedAddress] = useState( + null + ); const [showDropdown, setShowDropdown] = useState(false); const [triggerSearch, setTriggerSearch] = useState(false); const [loadingAddresses, setLoadingAddresses] = useState(false); @@ -46,12 +48,11 @@ export default function AddressSearch({ const validation = await refetch(); setTriggerSearch(false); - // Only continue if postcode is valid if (!validation.data || validation.data.status !== 200) return; - // Fetch addresses from backend setLoadingAddresses(true); setAddressError(null); + try { const res = await fetch( `/api/postcode/${encodeURIComponent(postcode)}/addresses` @@ -62,12 +63,16 @@ export default function AddressSearch({ setAddressError(json.error || "Unable to retrieve addresses"); setShowDropdown(false); } else if (json.results?.length) { - setAddresses(json.results); + const mapped = json.results.map((r: any) => ({ + address: r.address, + uprn: r.uprn, + })); + setAddresses(mapped); setShowDropdown(true); } else { setAddressError("No addresses found for this postcode"); } - } catch (err: any) { + } catch { setAddressError("There was an issue contacting the address service."); } finally { setLoadingAddresses(false); @@ -75,9 +80,10 @@ export default function AddressSearch({ } function handleSelectAddress(value: string) { - setSelectedAddress(value); + const selected = addresses.find((a) => a.address === value) || null; + setSelectedAddress(selected); setShowDropdown(false); - onAddressSelect(value); + onAddressSelect(selected); // ✅ This now matches the correct type } function handleChangeAddress() { @@ -88,7 +94,6 @@ export default function AddressSearch({ const showInvalid = data && data.status === 404; const showServerError = data && data.status === 500; - const isLoading = isFetching || loadingAddresses; return ( @@ -115,7 +120,7 @@ export default function AddressSearch({

)} - {/* Validation or server errors */} + {/* Validation and errors */} {showInvalid && (

Invalid postcode — please check and try again. @@ -138,7 +143,7 @@ export default function AddressSearch({ onPostcodeSelect(e.target.value.toUpperCase())} - className="text-lg" /> +

+
+

+ Selected Address +

+

+ {selectedAddress.address} +

+
+
+ +
)} diff --git a/src/app/portfolio/[slug]/remote-assessment/RemoteAssessmentClient.tsx b/src/app/portfolio/[slug]/remote-assessment/RemoteAssessmentClient.tsx index 8b6b436..d662b1e 100644 --- a/src/app/portfolio/[slug]/remote-assessment/RemoteAssessmentClient.tsx +++ b/src/app/portfolio/[slug]/remote-assessment/RemoteAssessmentClient.tsx @@ -1,13 +1,15 @@ "use client"; import { useState } from "react"; +import { useRouter } from "next/navigation"; +import { motion } from "framer-motion"; import AddressSearch from "./AddressSearch"; import ScenarioSetup from "./ScenarioSetup"; -import { ScenarioSelect } from "@/app/db/schema/recommendations"; -import { measuresList } from "@/app/db/schema/recommendations"; +import { ScenarioSelect, measuresList } from "@/app/db/schema/recommendations"; import useCreateRemoteAssessment from "./useCreateRemoteAssessment"; import { RemoteAssessmentFormValues } from "@/app/portfolio/[slug]/components/FormSchema"; import BackToPortfolioButton from "@/app/components/building-passport/BackToPortfolioButton"; +import { MapPin, ClipboardCheck, Zap } from "lucide-react"; export default function RemoteAssessmentClient({ portfolioId, @@ -16,6 +18,7 @@ export default function RemoteAssessmentClient({ portfolioId: string; scenarios: ScenarioSelect[]; }) { + const router = useRouter(); const [selectedAddress, setSelectedAddress] = useState<{ address: string; uprn: string; @@ -38,40 +41,124 @@ export default function RemoteAssessmentClient({ async function onSubmitRemoteAssessment(values: RemoteAssessmentFormValues) { await submitAssessment(values); + router.push(`/portfolio/${portfolioId}/plan-loading`); } return ( -
-
- -

Remote Assessment

+
+ {/* --- HERO / EXPLANATION SECTION --- */} +
+
+ +
+ {/* Title & back button pinned to top */} +
+ +

+ Remote Assessment +

+
+ + {/* Hero text split to use horizontal space better */} +
+

+ Domna IQ analyses your property data, models retrofit options, and + estimates potential funding — all without an on-site survey. +

+

+ Start by selecting your property, then choose retrofit goals and + configurations. Our model will generate your baseline and plan. + This isn't a replacement for an on-site survey but a powerful + first step. +

+
+ + {/* Step indicators */} +
+
+ Find Address +
+
+
+ Configure Scenario +
+
+
+ Generate Plan +
+
+
+ + {/* Optional subtle fade transition into workspace */} +
- + {/* --- TWO-COLUMN WORKSPACE --- */} +
+
+ {/* LEFT: Address Search */} + +
+

+ Step 1: Find your property +

+

Address lookup

+
-
- + setSelectedAddress(addr)} + onPostcodeSelect={setSelectedPostcode} + postcode={selectedPostcode} + /> + + + {/* RIGHT: Scenario Setup */} + +
+

+ Step 2: Configure scenario +

+

Your model setup

+
+ +
+ +
+
+
+
+ + {/* --- FOOTER NOTE --- */} +
+ All assessments use verified EPC, OS AddressBase, and open data sources.
); diff --git a/src/app/portfolio/[slug]/remote-assessment/ScenarioSetup.tsx b/src/app/portfolio/[slug]/remote-assessment/ScenarioSetup.tsx index 72eec37..7afb228 100644 --- a/src/app/portfolio/[slug]/remote-assessment/ScenarioSetup.tsx +++ b/src/app/portfolio/[slug]/remote-assessment/ScenarioSetup.tsx @@ -82,6 +82,7 @@ export default function ScenarioSetup({ const { setValue, watch, handleSubmit, formState } = form; const values = watch(); + const [localSubmitting, setLocalSubmitting] = useState(false); const scenarioOptions: ScenarioOption[] = useMemo( () => @@ -130,10 +131,10 @@ export default function ScenarioSetup({ } } - function onSubmit(data: RemoteAssessmentFormValues) { - console.log("form Data", data); - onSubmitRemoteAssessment(data); - console.log("Submitted scenario data:", data); + async function onSubmit(data: RemoteAssessmentFormValues) { + setLocalSubmitting(true); + // Keep the button in submitting state until redirect completes + await onSubmitRemoteAssessment(data); } return ( @@ -144,10 +145,6 @@ export default function ScenarioSetup({ : "opacity-100 cursor-default" }`} > -

- Step 2: Select or Create Scenario -

-
@@ -289,7 +286,7 @@ export default function ScenarioSetup({