diff --git a/CLAUDE.md b/CLAUDE.md index 5fd0594b..c87b3c04 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -10,6 +10,29 @@ - **Avoid `useEffect` and `useMemo`.** Derive values inline, prefer Server Components + Route Handlers, prefer event handlers. If a hook is genuinely the only option, flag it and ask before using it. - **Use TanStack Query (`@tanstack/react-query`), not raw `fetch`, for client-side HTTP.** Reads use `useQuery`; writes use `useMutation`. This project is on **v4** — note that `refetchInterval`'s callback signature is `(data, query)`, not v5's `(query)`. +## Dates + +- **`dd/mm/yyyy` everywhere a person reads or types a date.** This is a UK + product. `03/09/2026` is 3 September; rendering it as 3 March is silently + wrong data, not a cosmetic bug. +- **Never ``.** Its format follows the *browser's* locale, + so a US-configured browser shows `mm/dd/yyyy` and no attribute overrides it. + Use `DateInput` (`@/app/components/DateInput`) instead — it masks to + `dd/mm/yyyy`, carries a calendar picker, and its `value`/`onChange` stay + `YYYY-MM-DD`. +- **`YYYY-MM-DD` is the only format that crosses a boundary** — form state, + request bodies, Drizzle `date` columns. The display format stops at the + input's edge. Parsing/formatting helpers are in `@/utils/dates`; for output, + pass `"en-GB"` to `toLocaleDateString` / `Intl.DateTimeFormat`. +- See [ADR-0019](./docs/adr/0019-uk-date-format-in-form-inputs.md). + +## Utilities + +- **`src/utils/`** is for generic helpers — no domain knowledge (e.g. + `dates.ts`). **`src/app/utils.ts`** is for company-specific ones (EPC bands, + SAP points, portfolio ratings). `src/lib/utils.ts` is vendored Tremor/shadcn + class helpers — don't add to it. + ## Next.js 15 route handlers - `params` is a `Promise` — type as `{ params: Promise<{ ... }> }` and `await params` before destructuring. diff --git a/CONTEXT.md b/CONTEXT.md index 62859a70..62a4ee06 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -161,13 +161,17 @@ A category of works (Windows, Doors, Roofs, Electrical, Heating, …) — refere _Avoid_: measure (Measure is taken by the Scenarios domain), trade, work type **Stage**: -One step in a Project Workstream's ordered ladder (`project_workstream_stage`, positioned by `order`). Each Project Workstream owns its own ladder — different workstreams may follow different workflows. The v1 default ladder is Ordered / In progress / Completed / Charged / Closed, and the terminal stage is the one with the highest `order`. A Work order's stage FK (`work_order.project_workstream_stage_id`) is the **only lifecycle mechanism in v1** — `work_order.status`, `work_order.priority` and `project_workstream.current_stage_id` exist in the schema but are untouched. +One step in a Project Workstream's ordered ladder (`project_workstream_stage`, positioned by `order`). Each Project Workstream owns its own ladder — different workstreams may follow different workflows. The v1 default ladder is Ordered / In progress / Completed / Charged / Closed, and the terminal stage is the one with the highest `order`. A Work order's stage FK (`work_order.project_workstream_stage_id`) is the **only lifecycle mechanism in v1** — `work_order.status` and `project_workstream.current_stage_id` exist in the schema but are untouched. `work_order.priority` is now used, but it is not a lifecycle mechanism: see **Priority**. _Avoid_: status (the unused text column), phase, step **Work order**: One unit of work issued to a contractor: a (Property, Project Workstream Stage, contractor organisation, unique reference, forecast end date) row in `work_order`. Its position in the workflow is its Stage FK (see **Stage**). _Avoid_: job, ticket, task (a **Task** is the BulkUpload orchestration handle) +**Priority**: +A **flag on a Work order** (`work_order.priority`, boolean), meaning "look at this one first". It is a *stored* fact — someone marks it — and so is deliberately independent of **Overdue**, which is derived from the forecast end date and the Stage ladder: a flagged work order may be well inside its dates, and a late one nobody flagged is not a priority. Not a scale: there are no priority *levels* in v1, only flagged and not. +_Avoid_: urgency, severity, high/medium/low (there are no levels), escalation + **Evidence requirement** / **Evidence**: An **Evidence requirement** (`project_workstream_evidence_requirement`) is configuration: a required `file_type` (the existing enum) per Project Workstream, optionally narrowed to a single Stage. **Evidence** is a submission: an `uploaded_files` row with `file_source = 'projects'`, linked to its Work order (`work_order_id`) and optionally to the requirement it satisfies. Evidence is **advisory-only in v1** — badges and counts, never a gate: it does not block stage transitions and there is no approval state. _Avoid_: document (generic), attachment, proof diff --git a/cypress/e2e/projects/create-project.cy.js b/cypress/e2e/projects/create-project.cy.js new file mode 100644 index 00000000..25e38639 --- /dev/null +++ b/cypress/e2e/projects/create-project.cy.js @@ -0,0 +1,235 @@ +/** + * Ara Projects — projects list, empty state and create-project modal (#409) + * + * Two groups, because one of them writes: + * + * 1. The UI group stubs POST /api/projects with cy.intercept. It exercises + * the empty state, the modal, client-side validation and the navigation + * to workstream selection without touching the database, so it is safe to + * run anywhere. + * + * 2. The end-to-end group performs a real create and is the acceptance + * criterion's "create a project end-to-end". It INSERTs, so it is gated + * behind CYPRESS_ARA_PROJECTS_E2E_WRITES and must only ever be pointed at + * a non-production database. It also needs the #407 reference-data + * migration (0274) applied, or the project-type select will be empty and + * the page will not offer the CTA at all. + * + * Like the shell spec, this uses `cy.login` (cypress/support/commands.ts) to + * mint a real next-auth JWE cookie, so NEXTAUTH_JWT_SECRET must be set. + * + * NOT YET RUN. The environment this was written in has DATABASE_URL pointing at + * production, so Cypress was deliberately not executed. Treat the selectors and + * assertions below as unverified until someone runs them against a scratch DB. + */ + +const JWT_SECRET = Cypress.env("NEXTAUTH_JWT_SECRET"); +const E2E_WRITES = Cypress.env("ARA_PROJECTS_E2E_WRITES"); + +const INTERNAL_USER = { + email: "dev@domna.homes", + name: "Internal User", + onboarded: true, + sub: "cypress-internal", +}; + +describe("Ara Projects — create project (stubbed)", function () { + beforeEach(function () { + if (!JWT_SECRET) { + cy.log("NEXTAUTH_JWT_SECRET not set — skipping"); + this.skip(); + } + cy.login(INTERNAL_USER); + }); + + it("offers the Create project CTA from the list", function () { + cy.visit("/projects"); + + // The CTA sits inside the welcome card when there are no projects, and in + // the page header once there are — either way there is exactly one. + cy.get("[data-testid=create-project-trigger]").should("be.visible").click(); + cy.get("[data-testid=create-project-form]").should("be.visible"); + cy.contains("Project details").should("be.visible"); + }); + + it("shows the welcome empty state when the user has no visible projects", function () { + // Only meaningful on an instance with no projects visible to this user; + // where there are some, the list renders instead and this is skipped. + cy.visit("/projects"); + cy.get("body").then(($body) => { + if ($body.find("[data-testid=projects-list-empty]").length === 0) { + cy.log("user has visible projects — empty state not applicable"); + return; + } + cy.contains("Welcome to Ara Projects").should("be.visible"); + cy.contains("How setup works").should("be.visible"); + cy.get("[data-testid=create-project-trigger]").should("be.visible"); + }); + }); + + it("refuses to submit without a name and a project type", function () { + cy.visit("/projects"); + cy.get("[data-testid=create-project-trigger]").click(); + + cy.intercept("POST", "/api/projects", cy.spy().as("createCall")); + cy.get("[data-testid=create-project-submit]").click(); + + cy.contains("Enter a project name").should("be.visible"); + cy.get("@createCall").should("not.have.been.called"); + }); + + it("rejects an end date before the start date", function () { + cy.visit("/projects"); + cy.get("[data-testid=create-project-trigger]").click(); + + cy.get("[data-testid=create-project-name]").type("Backwards dates"); + cy.get("[data-testid=create-project-start-date]").type("30/09/2026"); + cy.get("[data-testid=create-project-end-date]").type("01/03/2026"); + cy.get("[data-testid=create-project-submit]").click(); + + cy.contains("The end date cannot be before the start date").should( + "be.visible", + ); + }); + + it("fills the field day-first from the calendar picker", function () { + cy.visit("/projects"); + cy.get("[data-testid=create-project-trigger]").click(); + + // Type a date first so the grid opens on a known month rather than + // whatever month the test happens to run in. + cy.get("[data-testid=create-project-start-date]").type("01/03/2026"); + cy.get("[data-testid=create-project-start-date-picker]").click(); + + // The grid is en-GB, so the week starts on Monday. + cy.get("[role=dialog]").within(() => { + cy.contains("Mo").should("be.visible"); + cy.contains("March 2026").should("be.visible"); + cy.get("[role=gridcell] button").contains(/^17$/).click(); + }); + + cy.get("[data-testid=create-project-start-date]").should( + "have.value", + "17/03/2026", + ); + }); + + it("formats the date as it is typed and rejects a day that does not exist", function () { + cy.visit("/projects"); + cy.get("[data-testid=create-project-trigger]").click(); + + // The separators are supplied by the field, so eight digits are enough. + cy.get("[data-testid=create-project-start-date]") + .type("31022026") + .should("have.value", "31/02/2026"); + + cy.get("[data-testid=create-project-name]").type("Impossible date"); + cy.intercept("POST", "/api/projects", cy.spy().as("createCall")); + cy.get("[data-testid=create-project-submit]").click(); + + // A finished-but-impossible date must not read as an empty optional field. + cy.contains("Enter a valid date").should("be.visible"); + cy.get("@createCall").should("not.have.been.called"); + }); + + it("navigates to workstream selection on success", function () { + cy.intercept("POST", "/api/projects", { + statusCode: 201, + body: { id: "4242" }, + }).as("createProject"); + + cy.visit("/projects"); + cy.get("[data-testid=create-project-trigger]").click(); + + cy.get("[data-testid=create-project-name]").type("Riverside retrofit 2026"); + selectFirstOption("create-project-organisation"); + selectFirstOption("create-project-type"); + cy.get("[data-testid=create-project-start-date]").type("01/03/2026"); + cy.get("[data-testid=create-project-domna-admin-access]").click(); + cy.get("[data-testid=create-project-submit]").click(); + + cy.wait("@createProject").then(({ request }) => { + expect(request.body.name).to.eq("Riverside retrofit 2026"); + expect(request.body.domnaAdminAccess).to.eq(true); + // Typed day-first, sent ISO: the display format stops at the input, and + // 01/03 is 1 March rather than 3 January. + expect(request.body.startDate).to.eq("2026-03-01"); + }); + + cy.location("pathname").should("eq", "/projects/4242/setup/workstreams"); + }); + + it("surfaces the server's error message on a refusal", function () { + cy.intercept("POST", "/api/projects", { + statusCode: 403, + body: { error: "You cannot create a project for that organisation." }, + }).as("createProject"); + + cy.visit("/projects"); + cy.get("[data-testid=create-project-trigger]").click(); + cy.get("[data-testid=create-project-name]").type("Not mine"); + selectFirstOption("create-project-organisation"); + selectFirstOption("create-project-type"); + cy.get("[data-testid=create-project-submit]").click(); + + cy.wait("@createProject"); + cy.get("[data-testid=create-project-error]") + .should("be.visible") + .and("contain", "cannot create a project for that organisation"); + cy.location("pathname").should("eq", "/projects"); + }); +}); + +describe("Ara Projects — create project (end to end, writes)", function () { + beforeEach(function () { + if (!JWT_SECRET || !E2E_WRITES) { + cy.log( + "ARA_PROJECTS_E2E_WRITES not set — skipping the writing happy path", + ); + this.skip(); + } + cy.login(INTERNAL_USER); + }); + + it("creates a project and lands on workstream selection", function () { + // Unique per run so repeated runs do not collide on a name a human is + // eyeballing later. `project.name` has no unique constraint; this is for + // legibility, not correctness. + const name = `Cypress project ${Date.now()}`; + + cy.visit("/projects"); + cy.get("[data-testid=create-project-trigger]").click(); + + cy.get("[data-testid=create-project-name]").type(name); + selectFirstOption("create-project-organisation"); + selectFirstOption("create-project-type"); + cy.get("[data-testid=create-project-description]").type( + "Created by the Cypress happy path.", + ); + cy.get("[data-testid=create-project-start-date]").type("01/03/2026"); + cy.get("[data-testid=create-project-end-date]").type("30/09/2026"); + // Required for an internal user creating on behalf of an organisation they + // are not a member of — without it the guard refuses, by design. + cy.get("[data-testid=create-project-domna-admin-access]").click(); + + cy.get("[data-testid=create-project-submit]").click(); + + cy.location("pathname").should("match", /^\/projects\/\d+\/setup\/workstreams$/); + + // The new project is now visible in the list, which is the visibility rule + // agreeing with the write that just happened. + cy.visit("/projects"); + cy.get("[data-testid=projects-list]").should("exist"); + cy.contains("[data-testid=projects-list-item]", name).should("be.visible"); + }); +}); + +/** + * Pick the first item in a shadcn/Radix `Select`. The options live in a portal + * outside the trigger, so this opens the trigger and then reaches for the + * listbox at the document root. + */ +function selectFirstOption(testId) { + cy.get(`[data-testid=${testId}]`).click(); + cy.get("[role=option]").first().click(); +} diff --git a/cypress/e2e/projects/projects-shell.cy.js b/cypress/e2e/projects/projects-shell.cy.js index 2676d9da..6e484d68 100644 --- a/cypress/e2e/projects/projects-shell.cy.js +++ b/cypress/e2e/projects/projects-shell.cy.js @@ -76,7 +76,17 @@ describe("Ara Projects route shell", function () { cy.get("[data-testid=projects-shell]").should("exist"); }); - it("renders the per-project dashboard shell and its nav", function () { + // This assertion changed with #409. While the authz stub was in place, + // `canViewProject` could never return false, so /projects/ rendered + // the dashboard shell for any signed-in user — which is what this test used + // to check. The real lib (#408) is now wired in, so a project the user has no + // standing on is a 404, and a project id that does not exist is the same 404 + // (deliberately indistinguishable, so Project existence does not leak). + // + // Rendering the dashboard shell therefore now needs a real, visible project, + // which is covered by the create-project happy path in create-project.cy.js + // rather than by a hardcoded id here. + it("404s on a project the user has no standing on", function () { cy.login({ email: "dev@domna.homes", name: "Internal User", @@ -84,13 +94,21 @@ describe("Ara Projects route shell", function () { sub: "cypress-internal", }); - cy.visit("/projects/1"); + cy.request({ url: "/projects/999999999", failOnStatusCode: false }) + .its("status") + .should("eq", 404); + }); - cy.get("[data-testid=project-shell]").should("exist"); - cy.get("[data-testid=project-dashboard-heading]").should("be.visible"); - - ["dashboard", "workOrders", "import", "settings"].forEach((item) => { - cy.get(`[data-testid=projects-nav-${item}]`).should("be.visible"); + it("404s on a malformed project id", function () { + cy.login({ + email: "dev@domna.homes", + name: "Internal User", + onboarded: true, + sub: "cypress-internal", }); + + cy.request({ url: "/projects/not-an-id", failOnStatusCode: false }) + .its("status") + .should("eq", 404); }); }); diff --git a/docs/adr/0019-uk-date-format-in-form-inputs.md b/docs/adr/0019-uk-date-format-in-form-inputs.md new file mode 100644 index 00000000..13b3a2aa --- /dev/null +++ b/docs/adr/0019-uk-date-format-in-form-inputs.md @@ -0,0 +1,102 @@ +# 19. Dates are entered and displayed as dd/mm/yyyy, not with `` + +Date: 2026-07-22 + +## Status + +Accepted + +Numbering note: 0015–0017 are in flight on the reporting-redesign branch +(PR #416), alongside 0010; 0019 follows ADR-0018 and avoids collision with all +of them. + +## Context + +This is a UK product. Everything we *display* already knows that — some forty +call sites pass `"en-GB"` to `toLocaleDateString` / `Intl.DateTimeFormat`, so a +rendered date reads `3 September 2026` or `03/09/2026`. + +Form **inputs** did not follow. Every date field in the app was +``, and the native control's display format is chosen by the +**browser's** locale, not the document's. A developer or user whose Chrome is +configured `en-US` sees `mm/dd/yyyy` in the same app that renders `dd/mm/yyyy` +everywhere else. + +That inconsistency is not cosmetic. `03/09/2026` is a valid date under both +readings — 3 September to a UK reader, 9 March to a US one. A user entering a +project's start date has no way to tell which one the box took, and no +validation can catch it, because both are dates. The failure mode is silently +wrong data written months into a works programme, not an error message. + +The `lang` attribute does not fix this: Chromium and Firefox both take the date +input's format from browser/OS locale settings and ignore document language. +There is no attribute, CSS property or polyfill that makes the native control +render day-first on demand. + +The options were: + +1. **Leave it.** Accept that the entry format varies per viewer. +2. **Use the native control but display the format in the label** — + "Start date (dd/mm/yyyy)". Honest, but a lie on a US-locale browser, where + the box then contradicts its own label. +3. **Replace the native control with a masked text input** that reads and + writes `dd/mm/yyyy`, keeping `YYYY-MM-DD` as the value, and supply our own + calendar to replace the native one it displaces. + +## Decision + +**`dd/mm/yyyy` is the date format for the whole app, in inputs as well as +output.** A date shown to or typed by a person is day-first, everywhere, for +every user, regardless of their browser's locale. + +**Date form fields use `DateInput` (`src/app/components/DateInput.tsx`), not +``.** It is a text input that masks to `dd/mm/yyyy` as the +user types, with a calendar picker in a popover, and whose `value`/`onChange` +remain `YYYY-MM-DD`. The parsing and formatting are pure functions in +`src/utils/dates.ts` (`formatUkDate`, `parseUkDate`, `formatUkDateWhileTyping`, +`isoToLocalDate`, `localDateToIso`), unit-tested independently of React. + +**`YYYY-MM-DD` remains the only format that crosses a boundary** — form state, +request bodies, Drizzle `date` columns. The display format stops at the input's +edge, so schemas, route handlers and the database are untouched by this +decision, and dates keep sorting lexicographically with no timezone in play. + +**Output keeps using `"en-GB"`** with `toLocaleDateString` / `Intl`. This ADR +does not introduce a second way to render a date; it makes entry agree with +what rendering already did. + +## Consequences + +- **The picker is replaced, not lost.** Dropping the native control also drops + its calendar, which was judged an acceptable cost — a picker is a + convenience, an ambiguous entry format is a correctness problem — but the + loss was immediately felt in use, so the calendar was rebuilt *behind* + `DateInput` as this ADR anticipated: a popover writing the same ISO value, + rather than a revert to the native control. It uses `react-day-picker` via + `shadcn_components/ui/calendar.tsx`, defaulting to the `enGB` locale, whose + `weekStartsOn: 1` puts Monday first. Typing and picking are equal routes to + the same value. +- **Two new dependencies**: `react-day-picker` and `date-fns` (the latter was + already present transitively; it is now direct). The alternative was a + hand-rolled month grid with no dependency, rejected because keyboard + navigation and ARIA on a calendar are easy to get subtly wrong and not worth + owning. +- **The `Date` boundary is confined to two functions.** A calendar works in + `Date`s, so `isoToLocalDate` / `localDateToIso` bridge to them — building and + reading *local* parts, never `new Date(iso)` or `toISOString()`, both of + which shift the day across midnight for a non-zero UTC offset. Everything + else in `src/utils/dates.ts` stays string-only. The round trip is tested + across a full month. +- **Caret handling is a masked input's usual compromise.** Typing at the end of + the field, which is the overwhelming case, behaves normally; editing in the + middle can move the caret to the end. Judged not worth a masking dependency. +- **A finished-but-impossible date is passed to the schema as typed** rather + than reported as empty, so `31/02/2026` produces "Enter a valid date" + instead of silently reading as an unfilled optional field. Unfinished input + reports empty, so no error appears mid-keystroke. +- **Migration is incremental.** `DateInput` is used by the create-project modal + (#409). Five other `` fields remain, in + `PibiSection.tsx`, `PibiDatesEditor.tsx` and `PropertyFilters.tsx`; they are + wrong under this ADR and should be converted when next touched. +- **New date fields have one right answer**, recorded in CLAUDE.md so it is + found before the wrong one is written. diff --git a/docs/adr/0019-work-order-import-is-setup-gated-and-carries-contractor-per-row.md b/docs/adr/0019-work-order-import-is-setup-gated-and-carries-contractor-per-row.md new file mode 100644 index 00000000..502275df --- /dev/null +++ b/docs/adr/0019-work-order-import-is-setup-gated-and-carries-contractor-per-row.md @@ -0,0 +1,104 @@ +# 19. Work-order import is the setup-gated final wizard step, and carries contractor per row + +Date: 2026-07-22 + +## Status + +Accepted + +Numbering note: 0015–0017 are in flight on the reporting-redesign branch, and +0010 alongside them (see ADR-0018's note). 0019 follows 0018 and avoids all of +them. + +## Context + +The Ara Projects "second import" (issue #414) matches a client-supplied +spreadsheet to Properties already in the DB and declares which Workstreams each +Property gets, as one row per (Property, Workstream). Committing those rows as +Work orders is #417. + +Two questions came up once the schema (PR #404) and the setup wizard shape +(wireframes 02–07) were concrete: + +1. **When is a project allowed to import?** A `work_order` row is + `(property, project_workstream_stage, project_workstream_contractor, + reference, forecast_end)` — all NOT NULL except `forecast_end`. So a Work + order cannot exist for a workstream that has no stage ladder and no assigned + contractor. Importing against a half-configured project would fail row by + row at commit with nothing the user could act on up front. + +2. **Where does each row's contractor come from?** The original #417 sketch + derived the contractor from the workstream: each `project_workstream` was + assumed to have a single contractor assignment, so the importer would look + it up and every Work order for that workstream went to that one org. But + `project_workstream_contractor` is a **collection** — a workstream can have + more than one contractor assigned (CONTEXT.md, "Contractor"), and real + programmes split one workstream's properties across several contractors by + area or batch. A single-assignee lookup cannot express that. + +## Decision + +**Import is the final, setup-gated step of the setup wizard.** + +- The wizard's earlier steps select workstreams, configure each workstream's + stage ladder, and assign contractors. Import is the last step; #413 routes + the wizard into this same `/projects/[projectId]/import` screen. It also + stays reachable standalone from its own nav button. +- The screen is **gated on setup completeness** regardless of entry point. + Rule: every `project_workstream` on the project must have **≥1 + `project_workstream_stage` AND ≥1 `project_workstream_contractor`**, and the + project must have at least one workstream. Until then the drop zone is + replaced by a "finish setup" state naming the incomplete workstreams and + linking back to configuration — not a 404 and not a silent empty zone. +- Evidence requirements (#412) are advisory and are **not** part of the gate. +- The gate is computed by `computeImportReadiness` (pure) / + `loadImportReadiness` (one read-only query) in + `src/lib/projects/import/readiness.ts`, returning per-workstream detail so + both this page and #413 can render *what* is missing. + +**Contractor is supplied per import row.** + +- The template gains a required `Contractor` column. Each row names the + contractor that delivers that (Property, Workstream), and it must match a + contractor **already assigned** to that workstream via + `project_workstream_contractor`. Validation (#417) rejects a contractor that + is not an existing assignment. +- **Contractor creation is out of scope for import.** Bringing a new company + into Ara and assigning it to a workstream is owned by the pre-existing + "invite company to Ara" flow; import only references assignments that flow + has already made. This is why the gate requires a contractor per workstream + before import opens — the assignments must exist first. + +**Stage is optional per row.** + +- The template gains an optional `Stage` column. A blank stage falls back at + commit to the workstream's first stage (`project_workstream_stage` ordered by + `order`, ascending — the ladder's start; see CONTEXT.md, "Stage"). A named + stage must match one on that workstream's ladder. + +The raw parser (`parse.ts`) stays header-agnostic: it does not enforce the +required/optional distinction or that names resolve. Required-ness is the +mapping step's job (#415) and value resolution is the commit step's (#417). + +## Consequences + +- **Trade-off vs the replaced #417 design.** Deriving the contractor from the + workstream's single assignee was simpler — one fewer required column, and no + per-row contractor to validate. We give that up because it silently assumed + one contractor per workstream, which the schema does not guarantee and real + programmes violate. Carrying the contractor per row costs the client a column + they must fill and a validation failure mode ("contractor X isn't assigned to + workstream Y"), but it is the only shape that supports a workstream split + across contractors, and it keeps the assignment set — not the spreadsheet — + as the source of truth for who may receive work. +- The setup gate means a project cannot reach the drop zone mid-configuration. + That is the intended safety property (no un-committable imports), but it does + make import unreachable until contractors are assigned — acceptable because + assignment is a prerequisite for issuing any work order at all. +- `readiness.ts` has two consumers (this page and #413), so its interface is + kept deliberately stable and detail-rich. +- Not yet decided here: how a row's named contractor disambiguates when the + same org is assigned to a workstream more than once, and the exact + stage-name matching rule. Both are #417's to settle at commit; this ADR fixes + only that the contractor is per-row-and-pre-assigned and the stage is + optional-with-first-stage-fallback. diff --git a/docs/adr/0020-import-session-and-mapping-are-client-held.md b/docs/adr/0020-import-session-and-mapping-are-client-held.md new file mode 100644 index 00000000..46224315 --- /dev/null +++ b/docs/adr/0020-import-session-and-mapping-are-client-held.md @@ -0,0 +1,91 @@ +# 20. The work-order import session — and the mapping persisted alongside it — is client-held + +Date: 2026-07-23 + +## Status + +Accepted + +Numbering note: two ADRs carry 0019 (the UK date format one, and the +work-order-import one from #414's branch). 0020 follows both. + +## Context + +Issue #415 (import step 2 of 3) asks for two mapping layers over the parsed +file — column mapping and value mapping — and for the result to be +"persist[ed] alongside the import session". + +The import journey has no session row. #414 decided that the parse route holds +nothing: it reads the uploaded file, returns **every** row to the browser, and +writes nothing. The mapping, validation and commit steps all read that array +from the import screen's React state, and commit (#417) is the first and only +write. There is no `import_session` table, no staged file in S3, and no +`work_order` row until the user commits. + +So "alongside the import session" had to be given a meaning. Three options: + +1. **A database session.** Add `import_session` (file identity, status, a JSONB + mapping), write it when the file is parsed, PATCH it as the user maps. +2. **Browser storage.** Keep the session in React state and mirror it to + `sessionStorage` so a refresh can restore it. +3. **A client-held session object.** Define `ImportSession` — file identity plus + both mapping layers — hold it in the import screen's state next to the parsed + rows, and hand it to commit. + +## Decision + +**Option 3.** `src/lib/projects/import/session.ts` defines `ImportSession`; the +import screen owns one, the mapping component edits it, and #417 will POST it +with the rows at commit. + +The shape is deliberately **JSON-clean end to end** — plain objects, string ids +(every `bigserial` is stringified at `mappingTargets`), no `bigint`, no `Date`, +no class instances. It can be POSTed verbatim and stored in a JSONB column +unchanged, which is how `bulk_address_uploads.column_mapping` already holds the +older BulkUpload journey's equivalent. + +`sessionMatchesFile` guards resumption: a mapping is a set of **column +indices**, so a session is meaningless against a file whose headings differ, and +restoring one would silently map the wrong columns. + +### Why not the database session + +Persisting the mapping without the rows buys the user nothing. The rows are +client-held, so a refresh loses them regardless; the user must re-upload, and a +restored mapping cannot be applied to a file that is no longer in hand. A +session row would therefore be durable state that no journey can currently +resume from — and it would cost a migration, a status lifecycle, a PATCH +endpoint and an expiry story to earn it. + +There is also a constraint worth recording plainly: this branch works against a +shared production database and was scoped to write nothing — no migrations. That +ruled option 1 out for *this* ticket, but it is not the reason it was rejected; +the reason is that the rows and the mapping have to be durable together or +neither is useful. + +### Why not `sessionStorage` + +It survives a refresh, but only for the mapping — the rows still do not, so the +restored mapping has no file to apply to. It also has to be read at mount, which +in a server-rendered client component means either a hydration mismatch or an +effect, and this codebase avoids `useEffect` by convention. + +## Consequences + +- A page refresh loses the import in progress, and the user re-uploads. This is + unchanged from #414, and the mapping does not make it worse. +- Stepping back to the drop zone and forward again does **not** lose the + mapping: the session lives in `ImportUpload`, above the mapping component, so + the mapping component may unmount freely. This is why every edit reports the + whole session upward rather than only living in the table's own state. +- No server-side record exists of who mapped what, or of a mapping that was + never committed. Nothing in v1 asks for one; if audit becomes a requirement, + it lands with the session row, not before. +- Two mapping layers on 20,000 rows are re-derived on every edit rather than + cached. That is affordable (a few passes over three cells per row) and is what + keeps the tables from disagreeing with the mapping the user is editing. +- **What would change the answer:** moving the file server-side. If the parsed + rows are ever staged (S3, or a rows table) — which is the natural fix for + files too large to hold in the browser, and the shape the BulkUpload journey + already uses — then a session row becomes worth its cost, and `ImportSession` + is already the payload it would store. diff --git a/docs/adr/0021-contractor-permissions-are-per-assignment-shown-per-contractor.md b/docs/adr/0021-contractor-permissions-are-per-assignment-shown-per-contractor.md new file mode 100644 index 00000000..7ae631e5 --- /dev/null +++ b/docs/adr/0021-contractor-permissions-are-per-assignment-shown-per-contractor.md @@ -0,0 +1,100 @@ +# 21. Contractor permissions are per-assignment, shown per-contractor; a removal never cascades through work orders + +Date: 2026-07-23 + +## Status + +**Decision 1 superseded by [ADR-0022](./0022-contractor-permissions-are-edited-and-shown-per-workstream.md)** +(2026-07-23): permissions are now edited per workstream in a grid and shown per +workstream in an expandable sub-row, so no per-contractor `mixed` state exists +any more. Decisions 2 (removal never cascades through work orders) and 3 +(Continue leads to the import) stand, and the Context below still explains why +the unit of a permission is the assignment. + +Numbering note: two ADRs carry 0019 (the UK date format one, and the +work-order-import one from #414's branch). 0021 follows 0020. + +## Context + +Issue #413 asks for a contractors-and-permissions screen matching the wireframe +`06-contractors-permissions.html`: a table whose rows are **contractor +organisations**, each showing the workstreams it delivers plus an "Update +stages" and an "Upload docs" switch. + +The schema underneath disagrees about the unit. `project_workstream_contractor` +is one row per **(Project Workstream, organisation)** pair, and both permission +flags live on that row — deliberately, because the authz guards read them +per work order: `canUpdateStage` checks the flag on the assignment the work +order was issued under, not on the organisation (`@/lib/projects/authz`). Apex +may legitimately update stages on Windows and not on Roofs. + +So a table row is *n* rows of the table it renders, and one switch is *n* +booleans. Three things had to be decided. + +**1. What a switch shows when the assignments disagree.** Options: show the +majority; show `true` if any assignment has it; show a third state. + +**2. What removing a contractor means when work has been issued.** `work_order` +references its assignment by a **NOT NULL** FK +(`work_order.project_workstream_contractor_id`), and that FK is how a work order +knows which contractor holds it. Deleting an assignment with work orders against +it therefore either fails on the constraint, or requires deleting/reassigning +the work orders first. The issue is explicit that orders keep their FK and that +we "surface this rather than cascading". + +**3. Where the wizard goes next.** #413 was written as the last step before the +dashboard; the 2026-07-22 reframe made it the last *configuration* step, with +the work-order import (#414) as the wizard's terminal step. + +## Decision + +**1. Three states: `on`, `off`, `mixed`.** `permissionState` in +`src/app/api/projects/[projectId]/contractors/assignments.ts` reads a +contractor's assignments and returns `"mixed"` when they disagree. The switch +renders it amber and labelled, and clicking a mixed switch resolves **upwards**: +the write grants the permission on every workstream that contractor delivers. +Rounding a disagreement to on or off silently would either widen a permission +nobody granted or revoke one somebody did. + +The write path is the same shape: PATCH takes the whole assignment set for one +contractor and applies one pair of flags across it. Divergent flags can still be +written — by another surface, or by a future per-workstream editor — and the +table will keep reporting them honestly rather than pretending they cannot +exist. + +**2. A removal with work orders is refused, not cascaded and not confirmed +away.** `decideRemoval` returns `blocked` with the count and the workstreams +named; `?confirm=true` does not override it, because there is nothing for the +user to consent to — the delete is impossible while the FK stands. This matches +the identical decision #410 made for deselecting a workstream, so "work orders +pin their configuration in place" is one rule across the setup screens, not two. + +A removal that merely leaves a workstream with **no** contractor is different: +it is legal, it is sometimes what the user wants, and it is precisely what the +import gate (ADR-0019) then blocks on. That warns — `needs-confirmation`, one +`?confirm=true` away — rather than being refused. + +**3. Continue leads to the import.** The screen loads `loadImportReadiness` +(#414's shared helper) rather than deciding readiness itself, renders the +outstanding gaps when the project is not ready, and links Continue to +`/projects/[projectId]/import` regardless. The import screen renders the same +readiness detail from the same helper, so an incomplete project meets an +explanation there rather than a dead end here — and a disabled Continue that +cannot say why is avoided. + +## Consequences + +- The permissions table is a **projection**, not a mirror, of + `project_workstream_contractor`. Anything that needs the per-assignment truth + (the authz guards, work-order issue) must read the rows, never the projection. +- Granting a permission to a contractor grants it across every workstream that + contractor delivers on the project. Per-workstream permissions are still + expressible in the schema and are still enforced; there is simply no UI that + produces them in v1. A future per-workstream editor is additive — the `mixed` + state already exists to describe what it would create. +- A contractor cannot be taken off a project once work has been issued to it. + Withdrawing one mid-programme is a work-order operation first, and no screen + in this feature performs it. +- The setup wizard now has six steps, of which this is the fifth. The step + counter on the earlier screens (#410 renders "Step 2 of 5") predates the + reframe and should be reconciled with the same count. diff --git a/docs/adr/0021-stage-ladder-seeding-and-the-status-column.md b/docs/adr/0021-stage-ladder-seeding-and-the-status-column.md new file mode 100644 index 00000000..1a24e594 --- /dev/null +++ b/docs/adr/0021-stage-ladder-seeding-and-the-status-column.md @@ -0,0 +1,146 @@ +# 21. Stage ladders: seeded on entering setup, keyed on `workstream.id`, and `status` written once as a placeholder + +Date: 2026-07-23 + +## Status + +Accepted + +## Context + +Issue #411 builds the stage-configuration setup screen. Each Project +Workstream owns an ordered ladder (`project_workstream_stage`, positioned by +`order`), and the ladder is the **only** lifecycle mechanism in v1: a Work +order's position is its stage FK, and the terminal stage is the one with the +highest `order` (CONTEXT.md, **Stage**). `work_order.status`, +`work_order.priority` and `project_workstream.current_stage_id` are deliberately +untouched, deferred to #426. + +Four things about that had to be decided. + +### 1. Where the default ladder gets seeded + +Every selected workstream should start on the v1 default ladder — Ordered → In +progress → Completed → Charged → Closed — and be seeded **exactly once**, per +the issue's acceptance criteria. A workstream with no stages is what the import +readiness gate (#414) reports as incomplete, so the seed is what unlocks half +of import for that workstream. + +The candidates were: seed at workstream selection (#410's POST), seed on the +first GET of the stages API, or seed when the setup screen is entered. + +### 2. Which id the stage routes are keyed on + +Issue #411 specifies the CRUD routes as +`/api/projects/[projectId]/workstreams/[projectWorkstreamId]/stages`. That +directory cannot exist: #410 already owns +`/api/projects/[projectId]/workstreams/[workstreamId]` for the deselect +endpoint, and Next.js refuses two different slug *names* for the same dynamic +path segment — "You cannot use different slug names for the same dynamic path +(`projectWorkstreamId` !== `workstreamId`)". It is a hard failure at boot and at +build, not a warning, and it takes the whole app down rather than just these +routes. + +So the segment is shared, and the only question left is what the id in it means. + +### 3. `project_workstream_stage.status` + +The column is `text NOT NULL` with no database default (migration 0273). Its +value set is still TBC — the schema's own comment says so — and #411's +acceptance criteria say no writes to `status` anywhere. Those two facts +contradict: a stage row cannot be inserted without *some* value in a `NOT NULL` +column, so "seed the default ladder" and "never write `status`" cannot both be +taken literally. + +### 4. The optional per-stage dates + +`project_workstream_stage` carries nullable `start_date` and `due_date` +columns, and the issue asked for them to be exposed as optional inputs. On +review of the built screen they were rejected: a stage is a rung of a workflow, +not a piece of scheduled work, so there is no date it can meaningfully hold. +Delivery dates belong to a Work order (`work_order.forecast_end` already exists). + +## Decision + +**The stage routes are keyed on `workstream.id`**, the catalogue row — the same +id the shared `[workstreamId]` segment already means for #410's deselect. The +URL shape the issue asked for is unchanged (`/workstreams/9/stages`); only the +id space is. `findLadder(projectId, workstreamId)` resolves it to the +`project_workstream.id` that every write function takes, exactly once per +request, at the edge. + +**Seeding happens in the setup page's server component**, before it reads, and +only for a caller who may manage the project. `seedDefaultLadders(projectId)` +selects the project's `project_workstream` rows `FOR UPDATE`, re-reads their +stage counts under that lock, and inserts a default ladder only for those with +none. + +**Inserts write `status = "active"` as a placeholder, once, and no update path +ever touches the column again.** The constant lives in one place +(`PLACEHOLDER_STAGE_STATUS`) and is not exposed in the UI, not read by any +query, and not part of any API contract. It matches what +`seed-projects-dashboard.ts` already writes, so seeded and user-created rows +agree. + +**`start_date` and `due_date` are not exposed and never written.** They are +absent from the request schemas, the payload and the UI, so a ladder stage +leaves them NULL for every row this screen creates. The columns stay on the +table for now; whether they are dropped is a schema question deferred to a +later issue, and nothing in #411 depends on the answer. + +`project_workstream.current_stage_id` and `work_order.status` are genuinely +never written by #411 — the AC holds for both columns as stated. A stage that +`current_stage_id` points at cannot even be deleted from this screen. + +## Consequences + +- **One URL segment means one thing.** `/workstreams/9` and + `/workstreams/9/stages` name the same workstream. The alternative — keeping + `project_workstream.id` under a segment that means `workstream.id` one level + up — would have type-checked, passed its tests, and quietly addressed a + different workstream whenever the two ids diverged. Nothing in the URL would + have shown it. +- **The `project_workstream.id` never appears in a URL**, so it stays an + internal identifier. It is still what the readiness helper (#414) and the hub + (#444) pass around in-process, and it is still what the ladder payload carries + for the client that needs it. +- The resolution costs one extra join per request, on a query the handler was + making anyway to prove the workstream belongs to the project. +- **The seed is idempotent under concurrency, not merely on a revisit.** Two + simultaneous first visits cannot both find "no stages" and both insert: the + second transaction blocks on the row lock, then re-reads and finds the ladder. + "Seeded exactly once per workstream" is therefore true rather than likely. +- **A page render performs a write.** Unusual, and accepted deliberately: it is + the only trigger that satisfies "on entering this step" while still having the + first paint show the real ladder rather than an empty one that fills in + afterwards. It is idempotent, so a prefetch or a double render costs nothing + but a locked read. Seeding on GET was rejected for making a read endpoint + mutate; seeding in #410's POST was rejected because #411 must not edit that + route, and because a workstream selected before this decision existed would + never be seeded. +- **A read-only visitor sees empty ladders on a project nobody has configured + yet**, because seeding is skipped for them. That is honest — the workstream + genuinely has no stages, and the readiness gate says so — and it keeps a + viewer from creating rows. +- **The dates decision supersedes an acceptance criterion of #411**, which + asked for the date inputs. It was taken after seeing them on the screen, and + the issue should be amended rather than the code quietly diverging from it. +- **A stage-level date has nowhere to come back to cheaply**: reinstating the + inputs means a schema keep-or-drop decision first. That is the intended + order — the columns are unused rather than half-used in the meantime. +- **`status` carries no meaning and must not acquire one by accident.** Anything + reading it today would be reading a placeholder. When #426 agrees the value + set, that issue owns both the enum conversion and the backfill of rows written + here. +- If the column later gains a database default, the placeholder write can be + dropped with no other change: nothing depends on the value. + +## References + +- Issue #411 — Ara Projects: setup wizard 3/5, stage configuration +- Issue #410 — workstream selection, which owns the `[workstreamId]` segment +- CONTEXT.md, **Stage** and **Work order** +- [ADR-0019](./0019-work-order-import-is-setup-gated-and-carries-contractor-per-row.md) + — import is setup-gated, which is what makes an unseeded ladder visible to the + user as a blocker +- Migration `0273_normal_bloodstrike.sql` — the `project_workstream_stage` DDL diff --git a/docs/adr/0022-contractor-permissions-are-edited-and-shown-per-workstream.md b/docs/adr/0022-contractor-permissions-are-edited-and-shown-per-workstream.md new file mode 100644 index 00000000..aeb48ee9 --- /dev/null +++ b/docs/adr/0022-contractor-permissions-are-edited-and-shown-per-workstream.md @@ -0,0 +1,88 @@ +# 22. Contractor permissions are edited and shown per workstream + +Date: 2026-07-23 + +## Status + +Accepted. Supersedes decision 1 of +[ADR-0021](./0021-contractor-permissions-are-per-assignment-shown-per-contractor.md); +its other two decisions stand. + +## Context + +ADR-0021 kept the wireframe's shape: one table row per contractor organisation, +with an "Update stages" and an "Upload docs" **switch** on that row. Because +`project_workstream_contractor` stores those flags per (workstream, +organisation) pair, one switch stood for *n* booleans, and a contractor whose +assignments disagreed was reported as `mixed`. + +Building it exposed the flaw. A switch is a control that asserts one state and +sets one state; it cannot honestly represent *n*, so: + +- the `mixed` state needed a chip, a tooltip and a bespoke accessible name + before it was even comprehensible — a lot of explanation for a control that + was still lying about its own shape; +- the only write it could express was "apply one pair of flags to everything", + so the UI could **read** a per-workstream split but never **author** one. The + schema's central capability was unreachable from the only screen that + configures it, and ADR-0021 had to note that no v1 surface produced divergent + flags; +- clicking a `mixed` switch destroyed information the user might not have + looked at, and "resolve upwards" was a rule invented to make an unsuitable + control decidable. + +Meanwhile the actual question — *may this contractor move Windows along, and +may it upload evidence on Roofs?* — is a grid: workstreams down, permissions +across. And on the table, permissions are detail: who delivers what is the +scanning question, and every row spending two columns on flags nobody is +reading crowds it out. + +## Decision + +**Permissions are edited per workstream, in a grid.** The add/edit dialog shows +one row per workstream the *project* covers — not merely the ones this +contractor holds — with a tick to assign it and a tick per permission. +Unassigned rows stay visible and greyed, their permission boxes disabled: the +shape of the project is part of the decision, and a workstream nobody covers is +worth seeing at the moment someone is being assigned. Un-ticking a workstream +clears its permissions, so re-ticking it never silently restores a grant. Each +column header carries an all/none shortcut, because ticking twenty boxes by +hand is how mistakes get made. + +**The main table hides permissions until asked.** A row shows the contractor, +the workstreams it delivers, and its Actions. Clicking the row — or its +disclosure button, which is what carries `aria-expanded`/`aria-controls` for +keyboard and screen-reader users — opens a sub-row listing each assignment with +its two permissions, read-only. Several rows may be open at once; comparing two +contractors is a normal thing to want. Actions stay per contractor, since Edit +and Remove act on the whole assignment set. + +**The wire shape follows.** POST and PATCH take `assignments: [{ +projectWorkstreamId, updateStagesPermission, uploadDocumentsPermission }]` +instead of one id list plus one pair of flags. A workstream may appear only +once per request — two entries for the same workstream are two answers to one +question, and picking one silently is worse than a 400. `ContractorGroup` no +longer carries a per-contractor summary of either permission, and +`permissionState` is gone: nothing needs the flags reduced to one answer, and +reducing them is precisely how a contractor allowed to update stages on one +workstream comes to look allowed everywhere. + +## Consequences + +- The screen can now express what the schema always stored, and what the authz + guards have always enforced per assignment (`canUpdateStage` reads the flag on + the work order's own assignment). UI, storage and enforcement finally agree on + the unit. +- Divergent permissions are no longer an anomaly to be explained but the normal + output of an ordinary edit. The `mixed` vocabulary, its chip and its tooltip + are deleted rather than reworded. +- Setting one permission across many workstreams costs one click per box, or + one on the column header. That is more work than the single switch it + replaces — accepted deliberately: the switch was cheap because it was coarse. +- The table's first read is now "who delivers what", with permissions one click + away. A future need to scan permissions across contractors (an audit view) + would want a different surface, not these columns back. +- Editing permissions on one workstream sends the contractor's whole assignment + set. The removal rules still run over exactly the workstreams a request drops, + so an edit that also un-ticks a workstream with work orders is still refused + (ADR-0021, decision 2). diff --git a/docs/adr/0023-installation-in-progress-gated-on-design-document.md b/docs/adr/0023-installation-in-progress-gated-on-design-document.md new file mode 100644 index 00000000..6d76712c --- /dev/null +++ b/docs/adr/0023-installation-in-progress-gated-on-design-document.md @@ -0,0 +1,96 @@ +# 23. Installation in Progress is gated on the Retrofit Design Document, not the HubSpot designStatus flag + +Date: 2026-07-24 + +## Status + +Accepted + +## Context + +On the Live projects screen (`your-projects/live`), a Property's delivery stage +is derived from HubSpot deal fields by the stage classifier +(`resolveDisplayStage` → `classifyDeals` → `computeLiveTrackerData` in +`transforms.ts`). After coordination is complete, the classifier decided +*Design in Progress* vs *Installation in Progress* from the self-reported +`designStatus` text field: `designStatus === "UPLOADED"` meant "design is done, +installation can happen". + +That flag is set in the CRM independently of the actual design work. Observed +values include `"UPLOADED"`, `"uploaded"` and `"IN PROGRESS"`, and it is +routinely set before — or without — the **Retrofit Design Document** +(`retrofit_design_doc`) ever being uploaded. The CRM flag and the document store +are two independent sources of truth that had silently diverged, so large +numbers of Properties with no design in place showed as *Installation in +Progress*. Managers could not trust the pipeline counts, the funnel, or the +stage badges, and Properties genuinely waiting on design were hidden inside a +later stage. + +The domain owner confirmed there is only ever one design document per Property — +the Retrofit Design Document — and its presence is the correct trigger for +*Installation in Progress*. + +## Decision + +**Design-document presence, not the `designStatus` flag, drives the +Design-vs-Installation boundary.** + +- The classifier stops reading `designStatus`. `designStatus` remains on the + deal record and may still be displayed (and still feeds the separate design + throughput trends chart), but it no longer influences the stage. +- Whether a `retrofit_design_doc` exists for a deal is passed **into** the pure + classifier as an explicit input — `resolveDisplayStage(deal, hasDesignDoc)`, + `classifyDeals(deals, designDocDealIds)`, + `computeLiveTrackerData(deals, designDocDealIds)`. The classification + functions perform no I/O; presence is derived by + `deriveDesignDocDealIds(docsByDealId)` from the documents already fetched + (direct deal-id match and UPRN fallback), using `DESIGN_DOC_TYPES` as the + definition of a design document. `page.tsx` and `[dealId]/page.tsx` now fetch + documents ahead of classification so the same fetch feeds both the presence + set and the document-status map. + +- **After coordination, downstream evidence wins; document presence only + decides the Design/Installation boundary.** For a coordination-complete deal + (a `(V1|V2|V3) IOE/MTP COMPLETE` marker, not an RA issue) the stage resolves + in this priority: + + ``` + full lodgement date present → Project Complete + measures lodgement date present → At Post Survey + lodgement status present → At Lodgement + measures installed OR installer handover→ Installation Complete + Retrofit Design Document present → Installation in Progress + otherwise → Design in Progress + ``` + + Gating the whole post-coordination block on document presence would drag a + genuinely installed or lodged Property back to *Design in Progress* when its + design document is merely missing from the store. Document presence is the + weakest signal in the ladder, not a gate on the rest. + +- The document-status map's install bucket is corrected: a `retrofit_design_doc` + is no longer mis-bucketed as an install document, so a Property holding only a + design document is not reported as having install documents. + +Coordination and earlier stages are untouched — the RA-issue → Queries path, +the removed-Property short-circuits, the dealstage-id → raw-stage mapping and +the Coordination in Progress path all behave exactly as before. + +## Consequences + +- A Property shows *Installation in Progress* only once its Retrofit Design + Document exists; one whose coordination is complete but whose document is + missing stays at *Design in Progress*, where the outstanding design work is + visible. Funnel and stage-progress counts (and the "All Projects" roll-up) + follow the corrected per-deal classification, as does the Properties-tab stage + filter. +- A prematurely-set or stale `designStatus` flag can no longer push a Property + into *Installation in Progress*. +- `DESIGN_DOC_TYPES` (previously defined but unused) becomes load-bearing as the + single definition of what counts as a design document. +- Out of scope, deliberately: correcting the underlying `designStatus` data or + alerting on CRM-vs-document mismatch; surfacing a design-completeness badge on + the Documents tab; multi-document or per-measure design requirements (there is + only ever one design document per Property). The Live projects feature itself + remains superseded-in-principle by Ara Projects per ADR-0018; this fix keeps + it correct in the meantime. diff --git a/package-lock.json b/package-lock.json index 7bc83da5..12c9f9b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,6 +46,7 @@ "aws-sdk": "^2.1415.0", "class-variance-authority": "^0.6.1", "clsx": "^1.2.1", + "date-fns": "^4.4.0", "drizzle-orm": "^0.44.5", "esbuild": "^0.25.8", "eslint-config-next": "13.4.3", @@ -61,6 +62,7 @@ "postcss": "^8.5.6", "react": "18.3.1", "react-confetti": "^6.4.0", + "react-day-picker": "^10.0.1", "react-dom": "18.3.1", "react-hook-form": "^7.53.2", "recharts": "^3.8.1", @@ -1250,6 +1252,12 @@ "ms": "^2.1.1" } }, + "node_modules/@date-fns/tz": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@date-fns/tz/-/tz-1.5.0.tgz", + "integrity": "sha512-lwYN/vDPeNRULcepoE/LO2Pgx+7/RV+S9ARfbc9lr2DtGkOD7pAiruHvbR1RX3Qyf6ja47EWJDMsNK5vK08DJg==", + "license": "MIT" + }, "node_modules/@dnd-kit/accessibility": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz", @@ -6036,12 +6044,36 @@ "node": ">=6" } }, + "node_modules/@tremor/react/node_modules/date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/@tremor/react/node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "license": "MIT" }, + "node_modules/@tremor/react/node_modules/react-day-picker": { + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-8.10.2.tgz", + "integrity": "sha512-LK68OTbHB3oJNhl9cA0qVizzp3o26w61YSjAFkYi67N86iro32wx86kSNeFU/hq+gI8m1yzWhnomMLfZ041RzQ==", + "license": "MIT", + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/gpbl" + }, + "peerDependencies": { + "date-fns": "^2.28.0 || ^3.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/@tremor/react/node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", @@ -8528,9 +8560,9 @@ } }, "node_modules/date-fns": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", - "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.4.0.tgz", + "integrity": "sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==", "license": "MIT", "funding": { "type": "github", @@ -13283,17 +13315,29 @@ } }, "node_modules/react-day-picker": { - "version": "8.10.1", - "resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-8.10.1.tgz", - "integrity": "sha512-TMx7fNbhLk15eqcMt+7Z7S2KF7mfTId/XJDjKE8f+IUcFn0l08/kI4FiYTL/0yuOLmEcbR4Fwe3GJf/NiiMnPA==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-10.0.1.tgz", + "integrity": "sha512-eNh6BlwcYInWaJtRv18mXQ06Ys/H6rdTZAnTaSdOYJuTpwP1JMCHNd1FDRadA+gbeinq+psdULN5Xnowy9mV8w==", "license": "MIT", + "dependencies": { + "@date-fns/tz": "^1.4.1", + "date-fns": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, "funding": { "type": "individual", "url": "https://github.com/sponsors/gpbl" }, "peerDependencies": { - "date-fns": "^2.28.0 || ^3.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + "@types/react": ">=16.8.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, "node_modules/react-dom": { diff --git a/package.json b/package.json index 92fda474..5cee2c0b 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "aws-sdk": "^2.1415.0", "class-variance-authority": "^0.6.1", "clsx": "^1.2.1", + "date-fns": "^4.4.0", "drizzle-orm": "^0.44.5", "esbuild": "^0.25.8", "eslint-config-next": "13.4.3", @@ -73,6 +74,7 @@ "postcss": "^8.5.6", "react": "18.3.1", "react-confetti": "^6.4.0", + "react-day-picker": "^10.0.1", "react-dom": "18.3.1", "react-hook-form": "^7.53.2", "recharts": "^3.8.1", diff --git a/src/app/api/projects/[projectId]/contractors/[organisationId]/route.test.ts b/src/app/api/projects/[projectId]/contractors/[organisationId]/route.test.ts new file mode 100644 index 00000000..363b0d74 --- /dev/null +++ b/src/app/api/projects/[projectId]/contractors/[organisationId]/route.test.ts @@ -0,0 +1,397 @@ +/** + * PATCH / DELETE `/api/projects/[projectId]/contractors/[organisationId]` + * (issue #413). + * + * The database is mocked at the module boundary (`../queries` and the authz + * repository); no connection is opened. Both the authorization decisions + * (`@/lib/projects/authz`) and the removal rules (`../assignments`) are the + * real ones — only the facts they read are faked. + */ +import { describe, expect, it, beforeEach, vi } from "vitest"; +import { NextRequest } from "next/server"; + +const { + mockGetServerSession, + mockLoadAuthzUser, + mockLoadProjectAuthzFacts, + mockFindContractorAssignments, + mockListProjectWorkstreams, + mockCountOtherContractors, + mockWriteContractorAssignments, + mockDeleteAssignments, +} = vi.hoisted(() => ({ + mockGetServerSession: vi.fn(), + mockLoadAuthzUser: vi.fn(), + mockLoadProjectAuthzFacts: vi.fn(), + mockFindContractorAssignments: vi.fn(), + mockListProjectWorkstreams: vi.fn(), + mockCountOtherContractors: vi.fn(), + mockWriteContractorAssignments: vi.fn(), + mockDeleteAssignments: vi.fn(), +})); + +vi.mock("next-auth", () => ({ getServerSession: mockGetServerSession })); +vi.mock("@/app/api/auth/[...nextauth]/authOptions", () => ({ AuthOptions: {} })); +vi.mock("@/app/repositories/projects/authzRepository", () => ({ + loadAuthzUser: mockLoadAuthzUser, + loadProjectAuthzFacts: mockLoadProjectAuthzFacts, +})); +vi.mock("../queries", () => ({ + findContractorAssignments: mockFindContractorAssignments, + listProjectWorkstreams: mockListProjectWorkstreams, + countOtherContractors: mockCountOtherContractors, + writeContractorAssignments: mockWriteContractorAssignments, + deleteAssignments: mockDeleteAssignments, +})); + +import { DELETE, PATCH } from "./route"; + +const CLIENT_ORG = "11111111-1111-1111-1111-111111111111"; +const CONTRACTOR_ORG = "22222222-2222-2222-2222-222222222222"; +const OTHER_ORG = "33333333-3333-3333-3333-333333333333"; +const APEX = "44444444-4444-4444-4444-444444444444"; + +const WORKSTREAMS = [ + { projectWorkstreamId: "10", name: "Windows", contractorCount: 1 }, + { projectWorkstreamId: "11", name: "Roofs", contractorCount: 1 }, +]; + +/** Apex delivers Windows and Roofs, with no work orders against either. */ +const CURRENT = [ + { + id: "100", + projectWorkstreamId: "10", + workstreamName: "Windows", + updateStagesPermission: true, + uploadDocumentsPermission: true, + workOrders: 0, + }, + { + id: "101", + projectWorkstreamId: "11", + workstreamName: "Roofs", + updateStagesPermission: true, + uploadDocumentsPermission: true, + workOrders: 0, + }, +]; + +function signedInAs(organisationIds: string[]) { + mockGetServerSession.mockResolvedValue({ user: { dbId: "7" } }); + mockLoadAuthzUser.mockResolvedValue({ + id: 7n, + email: "someone@landlord.example", + organisationIds, + }); +} + +function projectExists() { + mockLoadProjectAuthzFacts.mockResolvedValue({ + id: 5n, + organisationId: CLIENT_ORG, + domnaAdminAccess: false, + contractorOrganisationIds: [CONTRACTOR_ORG], + }); +} + +const params = (organisationId = APEX) => ({ + params: Promise.resolve({ projectId: "5", organisationId }), +}); + +function url(confirm = false, organisationId = APEX) { + return `http://test/api/projects/5/contractors/${organisationId}${ + confirm ? "?confirm=true" : "" + }`; +} + +/** One grid row: a workstream and the permissions it should carry. */ +function ws( + projectWorkstreamId: string, + updateStagesPermission = false, + uploadDocumentsPermission = false, +) { + return { + projectWorkstreamId, + updateStagesPermission, + uploadDocumentsPermission, + }; +} + +function patchRequest(body: unknown, confirm = false) { + return new NextRequest(url(confirm), { + method: "PATCH", + body: JSON.stringify(body), + }); +} + +function deleteRequest(confirm = false, organisationId = APEX) { + return new NextRequest(url(confirm, organisationId), { method: "DELETE" }); +} + +beforeEach(() => { + vi.clearAllMocks(); + mockFindContractorAssignments.mockResolvedValue(CURRENT); + mockListProjectWorkstreams.mockResolvedValue(WORKSTREAMS); + // By default another contractor covers everything Apex would give up. + mockCountOtherContractors.mockResolvedValue({ "10": 1, "11": 1 }); + mockWriteContractorAssignments.mockResolvedValue({ + created: 0, + updated: 1, + removed: 1, + }); + mockDeleteAssignments.mockResolvedValue(2); +}); + +describe("PATCH", () => { + it("replaces the contractor's workstreams and permissions", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + + const res = await PATCH( + patchRequest({ assignments: [ws("10", false, true)] }), + params(), + ); + + expect(res.status).toBe(200); + expect(mockWriteContractorAssignments).toHaveBeenCalledWith( + 5n, + APEX, + [ + { + projectWorkstreamId: 10n, + updateStagesPermission: false, + uploadDocumentsPermission: true, + }, + ], + "replace", + ); + }); + + it("does not consult the removal rules when nothing is dropped", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + + const res = await PATCH( + patchRequest({ assignments: [ws("10"), ws("11")] }), + params(), + ); + + expect(res.status).toBe(200); + expect(mockCountOtherContractors).not.toHaveBeenCalled(); + }); + + it("409s for confirmation when dropping a workstream strands it", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + mockCountOtherContractors.mockResolvedValue({ "11": 0 }); + + const res = await PATCH( + patchRequest({ assignments: [ws("10")] }), + params(), + ); + + expect(res.status).toBe(409); + const body = await res.json(); + expect(body).toMatchObject({ requiresConfirmation: true, blocked: false }); + expect(body.error).toContain("Roofs"); + expect(mockWriteContractorAssignments).not.toHaveBeenCalled(); + }); + + it("writes once the stranding warning is confirmed", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + mockCountOtherContractors.mockResolvedValue({ "11": 0 }); + + const res = await PATCH( + patchRequest({ assignments: [ws("10")] }, true), + params(), + ); + + expect(res.status).toBe(200); + expect(mockWriteContractorAssignments).toHaveBeenCalled(); + }); + + it("blocks dropping a workstream with work orders, even when confirmed", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + mockFindContractorAssignments.mockResolvedValue([ + CURRENT[0], + { ...CURRENT[1], workOrders: 4 }, + ]); + + const res = await PATCH( + patchRequest({ assignments: [ws("10")] }, true), + params(), + ); + + expect(res.status).toBe(409); + const body = await res.json(); + expect(body).toMatchObject({ blocked: true, requiresConfirmation: false }); + expect(body.error).toContain("4 work orders"); + expect(mockWriteContractorAssignments).not.toHaveBeenCalled(); + }); + + it("404s a contractor that is not assigned to the project", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + mockFindContractorAssignments.mockResolvedValue([]); + + const res = await PATCH( + patchRequest({ assignments: [ws("10")] }), + params(), + ); + + expect(res.status).toBe(404); + }); + + it("404s a workstream belonging to another project", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + + const res = await PATCH( + patchRequest({ assignments: [ws("999")] }), + params(), + ); + + expect(res.status).toBe(404); + expect(mockWriteContractorAssignments).not.toHaveBeenCalled(); + }); + + it("400s an empty workstream list — that is what DELETE is for", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + + const res = await PATCH(patchRequest({ assignments: [] }), params()); + + expect(res.status).toBe(400); + }); + + it("400s a contractor id that is not a uuid", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + + const res = await PATCH( + patchRequest({ assignments: [ws("10")] }), + params("apex"), + ); + + expect(res.status).toBe(400); + }); + + it("403s a contractor editing assignments", async () => { + signedInAs([CONTRACTOR_ORG]); + projectExists(); + + const res = await PATCH( + patchRequest({ assignments: [ws("10")] }), + params(), + ); + + expect(res.status).toBe(403); + }); + + it("404s a project the caller has no standing on", async () => { + signedInAs([OTHER_ORG]); + projectExists(); + + const res = await PATCH( + patchRequest({ assignments: [ws("10")] }), + params(), + ); + + expect(res.status).toBe(404); + }); +}); + +describe("DELETE", () => { + it("removes every assignment the contractor holds on the project", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + + const res = await DELETE(deleteRequest(), params()); + + expect(res.status).toBe(200); + await expect(res.json()).resolves.toEqual({ + organisationId: APEX, + removed: 2, + }); + expect(mockDeleteAssignments).toHaveBeenCalledWith([100n, 101n]); + }); + + it("409s for confirmation when removal strands a workstream", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + mockCountOtherContractors.mockResolvedValue({ "10": 1 }); + + const res = await DELETE(deleteRequest(), params()); + + expect(res.status).toBe(409); + const body = await res.json(); + expect(body.requiresConfirmation).toBe(true); + expect(body.error).toContain("Roofs"); + expect(mockDeleteAssignments).not.toHaveBeenCalled(); + }); + + it("removes once confirmed", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + mockCountOtherContractors.mockResolvedValue({}); + + const res = await DELETE(deleteRequest(true), params()); + + expect(res.status).toBe(200); + expect(mockDeleteAssignments).toHaveBeenCalled(); + }); + + it("blocks removing a contractor that has work orders", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + mockFindContractorAssignments.mockResolvedValue([ + { ...CURRENT[0], workOrders: 1 }, + CURRENT[1], + ]); + + const res = await DELETE(deleteRequest(true), params()); + + expect(res.status).toBe(409); + await expect(res.json()).resolves.toMatchObject({ blocked: true }); + expect(mockDeleteAssignments).not.toHaveBeenCalled(); + }); + + it("404s a contractor that is not assigned to the project", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + mockFindContractorAssignments.mockResolvedValue([]); + + const res = await DELETE(deleteRequest(), params()); + + expect(res.status).toBe(404); + }); + + it("403s a contractor removing anyone", async () => { + signedInAs([CONTRACTOR_ORG]); + projectExists(); + + const res = await DELETE(deleteRequest(), params()); + + expect(res.status).toBe(403); + expect(mockDeleteAssignments).not.toHaveBeenCalled(); + }); + + it("500s, without leaking the error, when the delete fails", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + mockDeleteAssignments.mockRejectedValue(new Error("pg exploded")); + const consoleError = vi + .spyOn(console, "error") + .mockImplementation(() => undefined); + + const res = await DELETE(deleteRequest(), params()); + + expect(res.status).toBe(500); + await expect(res.json()).resolves.toEqual({ + error: "Couldn't remove the contractor", + }); + consoleError.mockRestore(); + }); +}); diff --git a/src/app/api/projects/[projectId]/contractors/[organisationId]/route.ts b/src/app/api/projects/[projectId]/contractors/[organisationId]/route.ts new file mode 100644 index 00000000..6ba1c0c0 --- /dev/null +++ b/src/app/api/projects/[projectId]/contractors/[organisationId]/route.ts @@ -0,0 +1,181 @@ +/** + * `/api/projects/[projectId]/contractors/[organisationId]` (issue #413). + * + * PATCH — edit one contractor: which workstreams it delivers and what it may + * do on them. Replace semantics — the body is the assignment set the + * contractor should end up with. + * DELETE — remove the contractor from the project entirely. + * + * Both routes are removal paths, so both consult `decideRemoval` before they + * touch anything (see `../assignments` for the two rules). A refusal or a + * warning is a **409** carrying the reason: + * - `{ blocked: true }` — work orders exist; confirming won't help. + * - `{ requiresConfirmation: true }` — retry with `?confirm=true`. + * That is the same shape the workstream-deselect endpoint (#410) uses, so the + * client handles both the same way. + */ +import { NextRequest, NextResponse } from "next/server"; +import { z } from "zod"; +import { authorizeContractorRequest } from "../authorize"; +import { assignmentBodySchema, type AssignmentBody } from "../validation"; +import { decideRemoval, type ContractorAssignment } from "../assignments"; +import { + countOtherContractors, + deleteAssignments, + findContractorAssignments, + listProjectWorkstreams, + writeContractorAssignments, +} from "../queries"; + +type Params = { + params: Promise<{ projectId: string; organisationId: string }>; +}; + +/** Turn a removal decision into the 409 the client knows how to read. */ +async function refuseRemoval( + projectId: bigint, + organisationId: string, + removed: ContractorAssignment[], + confirmed: boolean, +): Promise { + if (removed.length === 0) return null; + + const remainingContractors = await countOtherContractors( + removed.map((a) => BigInt(a.projectWorkstreamId)), + organisationId, + ); + const decision = decideRemoval({ removed, remainingContractors }, confirmed); + if (decision.kind === "allowed") return null; + + return NextResponse.json( + { + error: decision.reason, + blocked: decision.kind === "blocked", + requiresConfirmation: decision.kind === "needs-confirmation", + }, + { status: 409 }, + ); +} + +/** + * PATCH — set exactly which workstreams this contractor delivers, and the + * permissions each of those carries. + * + * Workstreams dropped from the set are removed, so the removal rules apply to + * them. An empty set would be a removal of the whole contractor; that is what + * DELETE is for, and the schema rejects it here rather than quietly doing it. + */ +export async function PATCH(req: NextRequest, props: Params) { + const { projectId, organisationId } = await props.params; + const auth = await authorizeContractorRequest(projectId, "manage"); + if (!auth.ok) { + return NextResponse.json({ error: auth.error }, { status: auth.status }); + } + + if (!z.string().uuid().safeParse(organisationId).success) { + return NextResponse.json({ error: "Invalid contractor" }, { status: 400 }); + } + + let body: AssignmentBody; + try { + body = assignmentBodySchema.parse(await req.json()); + } catch { + return NextResponse.json({ error: "Invalid body" }, { status: 400 }); + } + + const current = await findContractorAssignments(auth.projectId, organisationId); + if (current.length === 0) { + return NextResponse.json( + { error: "Contractor not assigned to this project" }, + { status: 404 }, + ); + } + + const owned = new Set( + (await listProjectWorkstreams(auth.projectId)).map( + (w) => w.projectWorkstreamId, + ), + ); + if (body.assignments.some((a) => !owned.has(a.projectWorkstreamId))) { + return NextResponse.json( + { error: "Workstream not found on this project" }, + { status: 404 }, + ); + } + + const wanted = new Set(body.assignments.map((a) => a.projectWorkstreamId)); + const dropped = current.filter((a) => !wanted.has(a.projectWorkstreamId)); + const refusal = await refuseRemoval( + auth.projectId, + organisationId, + dropped, + req.nextUrl.searchParams.get("confirm") === "true", + ); + if (refusal) return refusal; + + try { + const result = await writeContractorAssignments( + auth.projectId, + organisationId, + body.assignments.map((a) => ({ + projectWorkstreamId: BigInt(a.projectWorkstreamId), + updateStagesPermission: a.updateStagesPermission, + uploadDocumentsPermission: a.uploadDocumentsPermission, + })), + "replace", + ); + return NextResponse.json({ organisationId, ...result }); + } catch (err) { + console.error( + "PATCH /api/projects/[projectId]/contractors/[organisationId] failed:", + err, + ); + return NextResponse.json( + { error: "Couldn't update the contractor" }, + { status: 500 }, + ); + } +} + +/** DELETE — take the contractor off the project, all workstreams at once. */ +export async function DELETE(req: NextRequest, props: Params) { + const { projectId, organisationId } = await props.params; + const auth = await authorizeContractorRequest(projectId, "manage"); + if (!auth.ok) { + return NextResponse.json({ error: auth.error }, { status: auth.status }); + } + + if (!z.string().uuid().safeParse(organisationId).success) { + return NextResponse.json({ error: "Invalid contractor" }, { status: 400 }); + } + + const current = await findContractorAssignments(auth.projectId, organisationId); + if (current.length === 0) { + return NextResponse.json( + { error: "Contractor not assigned to this project" }, + { status: 404 }, + ); + } + + const refusal = await refuseRemoval( + auth.projectId, + organisationId, + current, + req.nextUrl.searchParams.get("confirm") === "true", + ); + if (refusal) return refusal; + + try { + const removed = await deleteAssignments(current.map((a) => BigInt(a.id))); + return NextResponse.json({ organisationId, removed }); + } catch (err) { + console.error( + "DELETE /api/projects/[projectId]/contractors/[organisationId] failed:", + err, + ); + return NextResponse.json( + { error: "Couldn't remove the contractor" }, + { status: 500 }, + ); + } +} diff --git a/src/app/api/projects/[projectId]/contractors/assignments.test.ts b/src/app/api/projects/[projectId]/contractors/assignments.test.ts new file mode 100644 index 00000000..1c3db078 --- /dev/null +++ b/src/app/api/projects/[projectId]/contractors/assignments.test.ts @@ -0,0 +1,254 @@ +/** + * The pure contractor-assignment rules (issue #413). No database, no mocks — + * the module imports neither. + */ +import { describe, expect, it } from "vitest"; +import { + decideRemoval, + groupByContractor, + listNames, + type ContractorAssignment, + type ContractorAssignmentRow, +} from "./assignments"; + +const APEX = "11111111-1111-1111-1111-111111111111"; +const ELEVATE = "22222222-2222-2222-2222-222222222222"; + +function row( + overrides: Partial = {}, +): ContractorAssignmentRow { + return { + id: "1", + projectWorkstreamId: "10", + workstreamName: "Windows", + organisationId: APEX, + organisationName: "Apex Construction", + updateStagesPermission: true, + uploadDocumentsPermission: true, + workOrders: 0, + ...overrides, + }; +} + +function assignment( + overrides: Partial = {}, +): ContractorAssignment { + return { + id: "1", + projectWorkstreamId: "10", + workstreamName: "Windows", + updateStagesPermission: true, + uploadDocumentsPermission: true, + workOrders: 0, + ...overrides, + }; +} + +describe("groupByContractor", () => { + it("gathers per-workstream rows under one row per organisation", () => { + const groups = groupByContractor([ + row({ id: "1", projectWorkstreamId: "10", workstreamName: "Windows" }), + row({ id: "2", projectWorkstreamId: "11", workstreamName: "Roofs" }), + ]); + + expect(groups).toHaveLength(1); + expect(groups[0].organisationName).toBe("Apex Construction"); + expect(groups[0].assignments.map((a) => a.workstreamName)).toEqual([ + "Roofs", + "Windows", + ]); + }); + + it("orders organisations by name and workstreams by name", () => { + const groups = groupByContractor([ + row({ id: "1", workstreamName: "Windows" }), + row({ + id: "2", + projectWorkstreamId: "11", + workstreamName: "Doors", + organisationId: ELEVATE, + organisationName: "Elevate Electric", + }), + row({ id: "3", projectWorkstreamId: "12", workstreamName: "Asbestos" }), + ]); + + expect(groups.map((g) => g.organisationName)).toEqual([ + "Apex Construction", + "Elevate Electric", + ]); + expect(groups[0].assignments.map((a) => a.workstreamName)).toEqual([ + "Asbestos", + "Windows", + ]); + }); + + it("keeps each assignment's own permissions rather than reducing them", () => { + const groups = groupByContractor([ + row({ + id: "1", + workstreamName: "Windows", + updateStagesPermission: true, + uploadDocumentsPermission: false, + }), + row({ + id: "2", + projectWorkstreamId: "11", + workstreamName: "Roofs", + updateStagesPermission: false, + uploadDocumentsPermission: true, + }), + ]); + + expect(groups[0].assignments).toEqual([ + expect.objectContaining({ + workstreamName: "Roofs", + updateStagesPermission: false, + uploadDocumentsPermission: true, + }), + expect.objectContaining({ + workstreamName: "Windows", + updateStagesPermission: true, + uploadDocumentsPermission: false, + }), + ]); + // No per-contractor summary exists to disagree with the detail. + expect(groups[0]).not.toHaveProperty("updateStages"); + expect(groups[0]).not.toHaveProperty("uploadDocuments"); + }); + + it("totals work orders across the contractor's assignments", () => { + const groups = groupByContractor([ + row({ id: "1", workOrders: 3 }), + row({ id: "2", projectWorkstreamId: "11", workOrders: 4 }), + ]); + + expect(groups[0].workOrders).toBe(7); + }); + + it("returns nothing for a project with no assignments", () => { + expect(groupByContractor([])).toEqual([]); + }); +}); + +describe("listNames", () => { + it("joins with commas and a final 'and'", () => { + expect(listNames([])).toBe(""); + expect(listNames(["Windows"])).toBe("Windows"); + expect(listNames(["Windows", "Roofs"])).toBe("Windows and Roofs"); + expect(listNames(["Windows", "Roofs", "Doors"])).toBe( + "Windows, Roofs and Doors", + ); + }); +}); + +describe("decideRemoval", () => { + it("allows a removal that strands no workstream", () => { + const decision = decideRemoval( + { + removed: [assignment()], + remainingContractors: { "10": 1 }, + }, + false, + ); + + expect(decision).toEqual({ kind: "allowed" }); + }); + + it("warns when the workstream would be left with no contractor", () => { + const decision = decideRemoval( + { + removed: [assignment({ workstreamName: "Windows" })], + remainingContractors: { "10": 0 }, + }, + false, + ); + + expect(decision.kind).toBe("needs-confirmation"); + if (decision.kind !== "allowed") { + expect(decision.reason).toContain("Windows is left with no contractor"); + expect(decision.reason).toContain("imported"); + } + }); + + it("reads a missing remaining-count as zero", () => { + const decision = decideRemoval( + { removed: [assignment()], remainingContractors: {} }, + false, + ); + + expect(decision.kind).toBe("needs-confirmation"); + }); + + it("proceeds once the stranding warning is confirmed", () => { + const decision = decideRemoval( + { removed: [assignment()], remainingContractors: { "10": 0 } }, + true, + ); + + expect(decision).toEqual({ kind: "allowed" }); + }); + + it("blocks a removal whose assignment has work orders, naming the count", () => { + const decision = decideRemoval( + { + removed: [assignment({ workOrders: 12, workstreamName: "Roofs" })], + remainingContractors: { "10": 3 }, + }, + false, + ); + + expect(decision.kind).toBe("blocked"); + if (decision.kind !== "allowed") { + expect(decision.reason).toContain("12 work orders have"); + expect(decision.reason).toContain("Roofs"); + } + }); + + it("keeps blocking work orders even when the user confirms", () => { + const decision = decideRemoval( + { + removed: [assignment({ workOrders: 1 })], + remainingContractors: { "10": 0 }, + }, + true, + ); + + expect(decision.kind).toBe("blocked"); + }); + + it("sums work orders across the assignments being removed", () => { + const decision = decideRemoval( + { + removed: [ + assignment({ id: "1", workOrders: 2, workstreamName: "Windows" }), + assignment({ + id: "2", + projectWorkstreamId: "11", + workOrders: 3, + workstreamName: "Roofs", + }), + ], + remainingContractors: { "10": 1, "11": 1 }, + }, + false, + ); + + expect(decision.kind).toBe("blocked"); + if (decision.kind !== "allowed") { + expect(decision.reason).toContain("5 work orders"); + expect(decision.reason).toContain("Windows and Roofs"); + } + }); + + it("ignores assignments that are being kept when counting work orders", () => { + const decision = decideRemoval( + { + removed: [assignment({ workOrders: 0 })], + remainingContractors: { "10": 2 }, + }, + false, + ); + + expect(decision).toEqual({ kind: "allowed" }); + }); +}); diff --git a/src/app/api/projects/[projectId]/contractors/assignments.ts b/src/app/api/projects/[projectId]/contractors/assignments.ts new file mode 100644 index 00000000..2937705e --- /dev/null +++ b/src/app/api/projects/[projectId]/contractors/assignments.ts @@ -0,0 +1,178 @@ +/** + * Contractor-assignment rules for a Project (issue #413). + * + * Deliberately **pure** — it imports no database client and no React — so the + * route handlers, the unit tests and the browser bundle all share one copy of + * the rules. The rows themselves are loaded in `./queries`. + * + * Two things live here: + * + * 1. **Grouping.** `project_workstream_contractor` is one row per + * (Project Workstream, organisation) pair. The table has one row per + * *contractor organisation*, listing the workstreams it delivers, and + * expands to show the permissions each of those assignments carries — so + * grouping rearranges the rows without ever collapsing their permissions + * into a single per-contractor answer (ADR-0022). + * + * 2. **Removal.** Work orders reference their assignment by a NOT NULL FK + * (`work_order.project_workstream_contractor_id`), so an assignment with + * work orders against it cannot be deleted without cascading through + * issued work — which #413 explicitly rules out. Such a removal is + * therefore refused, with the count named, rather than attempted. A + * removal that merely leaves a workstream with no contractor is allowed, + * but warns first: that is exactly what the import gate gets stuck on + * (ADR-0019), so the user should hear it before it happens, not on the + * import screen afterwards. + */ + +/** One `project_workstream_contractor` row, flattened and serialised. */ +export interface ContractorAssignment { + /** `project_workstream_contractor.id`. */ + id: string; + /** `project_workstream.id` — the workstream this assignment delivers. */ + projectWorkstreamId: string; + /** `workstream.name`, for the chips and every warning sentence. */ + workstreamName: string; + updateStagesPermission: boolean; + uploadDocumentsPermission: boolean; + /** `work_order` rows issued against this assignment. Blocks removal. */ + workOrders: number; +} + +/** An assignment together with the organisation holding it. */ +export interface ContractorAssignmentRow extends ContractorAssignment { + organisationId: string; + organisationName: string; +} + +/** One row of the permissions table: a contractor and everything it delivers. */ +export interface ContractorGroup { + organisationId: string; + organisationName: string; + /** This contractor's assignments, ordered by workstream name. */ + assignments: ContractorAssignment[]; + /** Work orders across every assignment — non-zero means it cannot be removed. */ + workOrders: number; +} + +/** + * Gather per-workstream assignment rows under one row per contractor + * organisation, ordered by organisation name then workstream name so the table + * is stable between refetches. + * + * The permissions stay on the assignments. There is deliberately no + * per-contractor summary of them: the table's collapsed row shows who delivers + * what, and the expanded sub-row shows each assignment's own permissions + * (ADR-0022). Nothing needs the two flags reduced to one answer, and reducing + * them is how a contractor allowed to update stages on one workstream ends up + * looking allowed everywhere. + */ +export function groupByContractor( + rows: ContractorAssignmentRow[], +): ContractorGroup[] { + const groups = new Map(); + + for (const row of rows) { + let group = groups.get(row.organisationId); + if (!group) { + group = { + organisationId: row.organisationId, + organisationName: row.organisationName, + assignments: [], + workOrders: 0, + }; + groups.set(row.organisationId, group); + } + group.assignments.push({ + id: row.id, + projectWorkstreamId: row.projectWorkstreamId, + workstreamName: row.workstreamName, + updateStagesPermission: row.updateStagesPermission, + uploadDocumentsPermission: row.uploadDocumentsPermission, + workOrders: row.workOrders, + }); + } + + return [...groups.values()] + .map((group) => { + group.assignments.sort((a, b) => + a.workstreamName.localeCompare(b.workstreamName), + ); + return { + ...group, + workOrders: group.assignments.reduce((n, a) => n + a.workOrders, 0), + }; + }) + .sort((a, b) => a.organisationName.localeCompare(b.organisationName)); +} + +/** Which of the two flags is being talked about. */ +export type PermissionKey = + | "updateStagesPermission" + | "uploadDocumentsPermission"; + +/** `"Windows, Roofs and Doors"`. */ +export function listNames(names: string[]): string { + if (names.length === 0) return ""; + if (names.length === 1) return names[0]; + return `${names.slice(0, -1).join(", ")} and ${names[names.length - 1]}`; +} + +export type RemovalDecision = + | { kind: "blocked"; reason: string } + | { kind: "needs-confirmation"; reason: string } + | { kind: "allowed" }; + +/** The facts a removal is judged on. */ +export interface RemovalContext { + /** The assignments the request would delete. */ + removed: ContractorAssignment[]; + /** + * Keyed by `project_workstream.id`: how many *other* contractors would still + * be assigned to that workstream once these rows are gone. A key missing + * from the record is read as zero. + */ + remainingContractors: Record; +} + +/** + * Whether a removal may proceed. + * + * `confirmed` is the user having acknowledged the warning (`?confirm=true`). + * It never unblocks a work-order block: that is a hard rule, because the FK + * makes the delete impossible, not merely unwise. + */ +export function decideRemoval( + context: RemovalContext, + confirmed: boolean, +): RemovalDecision { + const withWork = context.removed.filter((a) => a.workOrders > 0); + if (withWork.length > 0) { + const total = withWork.reduce((n, a) => n + a.workOrders, 0); + const plural = total === 1 ? "work order has" : "work orders have"; + return { + kind: "blocked", + reason: + `${total} ${plural} already been issued to this contractor for ` + + `${listNames(withWork.map((a) => a.workstreamName))}. ` + + `Those work orders keep pointing at this assignment, so it can't be ` + + `removed — reassign or remove the work orders first.`, + }; + } + + const stranded = context.removed + .filter((a) => (context.remainingContractors[a.projectWorkstreamId] ?? 0) === 0) + .map((a) => a.workstreamName); + + if (!confirmed && stranded.length > 0) { + const plural = stranded.length === 1 ? "is" : "are"; + return { + kind: "needs-confirmation", + reason: + `${listNames(stranded)} ${plural} left with no contractor. ` + + `Work orders can't be imported until every workstream has one.`, + }; + } + + return { kind: "allowed" }; +} diff --git a/src/app/api/projects/[projectId]/contractors/authorize.ts b/src/app/api/projects/[projectId]/contractors/authorize.ts new file mode 100644 index 00000000..0459cbd6 --- /dev/null +++ b/src/app/api/projects/[projectId]/contractors/authorize.ts @@ -0,0 +1,16 @@ +/** + * Request authorization for the contractor-assignment endpoints (issue #413). + * + * The rule is the project-level one #408 already owns — view to read the + * table, manage to change it — and #410 already wired it up for the + * workstream-selection endpoints. Assigning a contractor is administering the + * project, exactly what `canManageProject` covers, so this re-exports that + * wiring under a name that reads right here rather than restating it. Nothing + * in this feature re-implements a permission rule. + */ +export { + authorizeWorkstreamRequest as authorizeContractorRequest, + type AuthorizeResult, + type AuthorizeSuccess, + type AuthorizeFailure, +} from "@/app/api/projects/[projectId]/workstreams/authorize"; diff --git a/src/app/api/projects/[projectId]/contractors/organisations/route.test.ts b/src/app/api/projects/[projectId]/contractors/organisations/route.test.ts new file mode 100644 index 00000000..abc683c8 --- /dev/null +++ b/src/app/api/projects/[projectId]/contractors/organisations/route.test.ts @@ -0,0 +1,112 @@ +/** + * GET `/api/projects/[projectId]/contractors/organisations` (issue #413). + * + * The search itself is mocked at `../queries`; what is tested here is that the + * picker is behind the manage permission and passes the query through. + */ +import { describe, expect, it, beforeEach, vi } from "vitest"; +import { NextRequest } from "next/server"; + +const { + mockGetServerSession, + mockLoadAuthzUser, + mockLoadProjectAuthzFacts, + mockSearchOrganisations, +} = vi.hoisted(() => ({ + mockGetServerSession: vi.fn(), + mockLoadAuthzUser: vi.fn(), + mockLoadProjectAuthzFacts: vi.fn(), + mockSearchOrganisations: vi.fn(), +})); + +vi.mock("next-auth", () => ({ getServerSession: mockGetServerSession })); +vi.mock("@/app/api/auth/[...nextauth]/authOptions", () => ({ AuthOptions: {} })); +vi.mock("@/app/repositories/projects/authzRepository", () => ({ + loadAuthzUser: mockLoadAuthzUser, + loadProjectAuthzFacts: mockLoadProjectAuthzFacts, +})); +vi.mock("../queries", () => ({ + searchOrganisations: mockSearchOrganisations, +})); + +import { GET } from "./route"; + +const CLIENT_ORG = "11111111-1111-1111-1111-111111111111"; +const CONTRACTOR_ORG = "22222222-2222-2222-2222-222222222222"; +const APEX = "44444444-4444-4444-4444-444444444444"; + +const RESULTS = [{ id: APEX, name: "Apex Construction", alreadyAssigned: false }]; + +function signedInAs(organisationIds: string[]) { + mockGetServerSession.mockResolvedValue({ user: { dbId: "7" } }); + mockLoadAuthzUser.mockResolvedValue({ + id: 7n, + email: "someone@landlord.example", + organisationIds, + }); +} + +function projectExists() { + mockLoadProjectAuthzFacts.mockResolvedValue({ + id: 5n, + organisationId: CLIENT_ORG, + domnaAdminAccess: false, + contractorOrganisationIds: [CONTRACTOR_ORG], + }); +} + +const params = { params: Promise.resolve({ projectId: "5" }) }; + +function request(query = "") { + return new NextRequest( + `http://test/api/projects/5/contractors/organisations${query}`, + ); +} + +beforeEach(() => { + vi.clearAllMocks(); + mockSearchOrganisations.mockResolvedValue(RESULTS); +}); + +describe("GET .../contractors/organisations", () => { + it("searches by the q parameter", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + + const res = await GET(request("?q=apex"), params); + + expect(res.status).toBe(200); + await expect(res.json()).resolves.toEqual({ + organisations: RESULTS, + limit: 20, + }); + expect(mockSearchOrganisations).toHaveBeenCalledWith(5n, "apex", 20); + }); + + it("treats a missing q as the empty search", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + + await GET(request(), params); + + expect(mockSearchOrganisations).toHaveBeenCalledWith(5n, "", 20); + }); + + it("403s a contractor — only managers may enumerate organisations", async () => { + signedInAs([CONTRACTOR_ORG]); + projectExists(); + + const res = await GET(request("?q=apex"), params); + + expect(res.status).toBe(403); + expect(mockSearchOrganisations).not.toHaveBeenCalled(); + }); + + it("401s without a session", async () => { + mockGetServerSession.mockResolvedValue(null); + + const res = await GET(request("?q=apex"), params); + + expect(res.status).toBe(401); + }); +}); diff --git a/src/app/api/projects/[projectId]/contractors/organisations/route.ts b/src/app/api/projects/[projectId]/contractors/organisations/route.ts new file mode 100644 index 00000000..3f13f07e --- /dev/null +++ b/src/app/api/projects/[projectId]/contractors/organisations/route.ts @@ -0,0 +1,38 @@ +/** + * `/api/projects/[projectId]/contractors/organisations?q=` (issue #413). + * + * The organisation picker behind "Add contractor". **Read-only, deliberately**: + * a contractor is an existing `organisation` (CONTEXT.md, "Contractor"), and + * creating one belongs to the "invite company to Ara" flow, not to project + * setup. There is no POST here and there should not be one. + * + * It is scoped to a project only for permission and for the `alreadyAssigned` + * flag — the organisation table itself is global. + */ +import { NextRequest, NextResponse } from "next/server"; +import { authorizeContractorRequest } from "../authorize"; +import { searchOrganisations } from "../queries"; + +type Params = { params: Promise<{ projectId: string }> }; + +/** How many matches the picker shows before asking the user to type more. */ +const RESULT_LIMIT = 20; + +export async function GET(req: NextRequest, props: Params) { + const { projectId } = await props.params; + // Manage, not view: only someone who could actually assign a contractor has + // any business enumerating organisations through this route. + const auth = await authorizeContractorRequest(projectId, "manage"); + if (!auth.ok) { + return NextResponse.json({ error: auth.error }, { status: auth.status }); + } + + const q = req.nextUrl.searchParams.get("q") ?? ""; + const organisations = await searchOrganisations( + auth.projectId, + q, + RESULT_LIMIT, + ); + + return NextResponse.json({ organisations, limit: RESULT_LIMIT }); +} diff --git a/src/app/api/projects/[projectId]/contractors/permissions.test.ts b/src/app/api/projects/[projectId]/contractors/permissions.test.ts new file mode 100644 index 00000000..756e86e3 --- /dev/null +++ b/src/app/api/projects/[projectId]/contractors/permissions.test.ts @@ -0,0 +1,148 @@ +/** + * The seam between what this feature *writes* and what the authz guards + * *read* (issue #413 acceptance: "permission toggles take effect in the authz + * lib guards"). + * + * The two ends are tested separately elsewhere — the guards' own rules in + * `@/lib/projects/authz`'s tests, the endpoints' behaviour in `./route.test.ts` + * — and neither notices if they stop describing the same booleans. This does: + * it starts from a `project_workstream_contractor` row typed against the real + * schema, flattens it exactly as `./queries` does, and asks the real guards + * what a contractor may do. Renaming a column or a wire field breaks it, at + * compile time or on the assertion. + * + * No database: the row is a literal, `InferModel` only supplies its type. + */ +import { describe, expect, it } from "vitest"; +import type { ProjectWorkstreamContractor } from "@/app/db/schema/projects/projects"; +import { + canUpdateStage, + canUploadEvidence, + type AuthzUser, + type ProjectAuthzFacts, + type WorkOrderAuthzFacts, +} from "@/lib/projects/authz"; +import type { ContractorAssignment } from "./assignments"; + +const CLIENT_ORG = "11111111-1111-1111-1111-111111111111"; +const APEX = "44444444-4444-4444-4444-444444444444"; + +/** Someone signed in for the contractor organisation, and nothing else. */ +const CONTRACTOR_USER: AuthzUser = { + id: 7n, + email: "site@apex.example", + organisationIds: [APEX], +}; + +const PROJECT: ProjectAuthzFacts = { + id: 5n, + organisationId: CLIENT_ORG, + domnaAdminAccess: false, + contractorOrganisationIds: [APEX], +}; + +/** A row as the table stores it, after the toggles have been set. */ +function storedRow( + updateStagesPermission: boolean, + uploadDocumentsPermission: boolean, +): ProjectWorkstreamContractor { + return { + id: 100n, + projectWorkstreamId: 10n, + organisationId: APEX, + updateStagesPermission, + uploadDocumentsPermission, + assignedAt: new Date("2026-07-23T09:00:00Z"), + }; +} + +/** The flattening `loadAssignmentRows` performs, in one place for the test. */ +function toWireAssignment(row: ProjectWorkstreamContractor): ContractorAssignment { + return { + id: row.id.toString(), + projectWorkstreamId: row.projectWorkstreamId.toString(), + workstreamName: "Windows", + updateStagesPermission: row.updateStagesPermission, + uploadDocumentsPermission: row.uploadDocumentsPermission, + workOrders: 0, + }; +} + +/** A work order issued under that assignment, as the guards read it. */ +function workOrderUnder( + assignment: ContractorAssignment, + organisationId = APEX, +): WorkOrderAuthzFacts { + return { + id: 900n, + contractorOrganisationId: organisationId, + updateStagesPermission: assignment.updateStagesPermission, + uploadDocumentsPermission: assignment.uploadDocumentsPermission, + }; +} + +describe("the permission toggles reach the authz guards", () => { + it("lets the contractor update stages only when the assignment grants it", () => { + const granted = toWireAssignment(storedRow(true, false)); + const withheld = toWireAssignment(storedRow(false, false)); + + expect( + canUpdateStage(CONTRACTOR_USER, PROJECT, workOrderUnder(granted)), + ).toBe(true); + expect( + canUpdateStage(CONTRACTOR_USER, PROJECT, workOrderUnder(withheld)), + ).toBe(false); + }); + + it("lets the contractor upload evidence only when the assignment grants it", () => { + const granted = toWireAssignment(storedRow(false, true)); + const withheld = toWireAssignment(storedRow(false, false)); + + expect( + canUploadEvidence(CONTRACTOR_USER, PROJECT, workOrderUnder(granted)), + ).toBe(true); + expect( + canUploadEvidence(CONTRACTOR_USER, PROJECT, workOrderUnder(withheld)), + ).toBe(false); + }); + + it("keeps the two permissions independent", () => { + const stagesOnly = toWireAssignment(storedRow(true, false)); + + expect( + canUpdateStage(CONTRACTOR_USER, PROJECT, workOrderUnder(stagesOnly)), + ).toBe(true); + expect( + canUploadEvidence(CONTRACTOR_USER, PROJECT, workOrderUnder(stagesOnly)), + ).toBe(false); + }); + + it("does not let a permission leak to a work order issued to another contractor", () => { + const granted = toWireAssignment(storedRow(true, true)); + const someoneElse = "55555555-5555-5555-5555-555555555555"; + + expect( + canUpdateStage( + CONTRACTOR_USER, + { ...PROJECT, contractorOrganisationIds: [APEX, someoneElse] }, + workOrderUnder(granted, someoneElse), + ), + ).toBe(false); + }); + + it("leaves the client organisation unaffected by the toggles", () => { + const withheld = toWireAssignment(storedRow(false, false)); + const clientUser: AuthzUser = { + id: 8n, + email: "asset@landlord.example", + organisationIds: [CLIENT_ORG], + }; + + expect( + canUpdateStage(clientUser, PROJECT, workOrderUnder(withheld)), + ).toBe(true); + expect( + canUploadEvidence(clientUser, PROJECT, workOrderUnder(withheld)), + ).toBe(true); + }); +}); diff --git a/src/app/api/projects/[projectId]/contractors/queries.ts b/src/app/api/projects/[projectId]/contractors/queries.ts new file mode 100644 index 00000000..20cdccac --- /dev/null +++ b/src/app/api/projects/[projectId]/contractors/queries.ts @@ -0,0 +1,412 @@ +/** + * Persistence for contractor assignment (issue #413). + * + * The route handlers and the server-rendered setup screen both read through + * here, so the first paint and every refetch afterwards agree on shape — the + * same split `./queries` gives the workstream-selection step (#410). + * + * Nothing in this file decides anything: the grouping and the removal rules + * live in `./assignments`, which imports no database client. Ids are bigint in + * the database and strings on the wire, because bigint does not survive JSON — + * the conversion happens here, at the boundary, and nowhere else. + */ +import { db } from "@/app/db/db"; +import { and, eq, ilike, inArray, isNotNull, ne, sql } from "drizzle-orm"; +import { + projectWorkstream, + projectWorkstreamContractor, + workOrder, + workstream, +} from "@/app/db/schema/projects/projects"; +import { organisation } from "@/app/db/schema/organisation"; +import { + groupByContractor, + type ContractorAssignment, + type ContractorAssignmentRow, + type ContractorGroup, +} from "./assignments"; + +/** One selectable workstream in the add/edit dialog. */ +export interface ProjectWorkstreamOption { + /** `project_workstream.id`, serialised. */ + projectWorkstreamId: string; + /** `workstream.name`. */ + name: string; + /** How many contractors are assigned to it — 0 is what blocks import. */ + contractorCount: number; +} + +/** One result of the organisation search behind "Add contractor". */ +export interface OrganisationOption { + /** `organisation.id` (uuid). */ + id: string; + name: string; + /** True when this organisation already delivers something on the project. */ + alreadyAssigned: boolean; +} + +/** Everything the permissions table renders. */ +export interface ContractorsView { + contractors: ContractorGroup[]; + workstreams: ProjectWorkstreamOption[]; +} + +/** + * Every `project_workstream_contractor` row on a project, flattened with the + * organisation, the workstream name and the count of work orders issued + * against it. + * + * The work-order count is `count(distinct)` over a left join: the count is + * load-bearing (it is what refuses a removal), so it must not be inflated by + * any other join fan-out. + */ +async function loadAssignmentRows( + projectId: bigint, + organisationId?: string, +): Promise { + const rows = await db + .select({ + id: projectWorkstreamContractor.id, + projectWorkstreamId: projectWorkstreamContractor.projectWorkstreamId, + workstreamName: workstream.name, + organisationId: projectWorkstreamContractor.organisationId, + organisationName: organisation.name, + updateStagesPermission: projectWorkstreamContractor.updateStagesPermission, + uploadDocumentsPermission: + projectWorkstreamContractor.uploadDocumentsPermission, + workOrders: sql`count(distinct ${workOrder.id})::int`, + }) + .from(projectWorkstreamContractor) + .innerJoin( + projectWorkstream, + eq(projectWorkstreamContractor.projectWorkstreamId, projectWorkstream.id), + ) + .innerJoin(workstream, eq(projectWorkstream.workstreamId, workstream.id)) + .innerJoin( + organisation, + eq(projectWorkstreamContractor.organisationId, organisation.id), + ) + .leftJoin( + workOrder, + eq(workOrder.projectWorkstreamContractorId, projectWorkstreamContractor.id), + ) + .where( + organisationId + ? and( + eq(projectWorkstream.projectId, projectId), + eq(projectWorkstreamContractor.organisationId, organisationId), + ) + : eq(projectWorkstream.projectId, projectId), + ) + .groupBy( + projectWorkstreamContractor.id, + workstream.name, + organisation.name, + ); + + return rows.map((row) => ({ + id: row.id.toString(), + projectWorkstreamId: row.projectWorkstreamId.toString(), + workstreamName: row.workstreamName, + organisationId: row.organisationId, + // `organisation.name` is nullable in the schema; a nameless organisation + // still has to render as something a user can point at. + organisationName: row.organisationName ?? "Unnamed organisation", + updateStagesPermission: row.updateStagesPermission, + uploadDocumentsPermission: row.uploadDocumentsPermission, + workOrders: row.workOrders, + })); +} + +/** The project's selected workstreams, with how many contractors each has. */ +export async function listProjectWorkstreams( + projectId: bigint, +): Promise { + const rows = await db + .select({ + projectWorkstreamId: projectWorkstream.id, + name: workstream.name, + contractorCount: sql`count(distinct ${projectWorkstreamContractor.id})::int`, + }) + .from(projectWorkstream) + .innerJoin(workstream, eq(projectWorkstream.workstreamId, workstream.id)) + .leftJoin( + projectWorkstreamContractor, + eq(projectWorkstreamContractor.projectWorkstreamId, projectWorkstream.id), + ) + .where(eq(projectWorkstream.projectId, projectId)) + .groupBy(projectWorkstream.id, workstream.name) + .orderBy(workstream.name); + + return rows.map((row) => ({ + projectWorkstreamId: row.projectWorkstreamId.toString(), + name: row.name, + contractorCount: row.contractorCount, + })); +} + +/** The whole permissions table for one project, in one place. */ +export async function loadContractorsView( + projectId: bigint, +): Promise { + const [rows, workstreams] = await Promise.all([ + loadAssignmentRows(projectId), + listProjectWorkstreams(projectId), + ]); + return { contractors: groupByContractor(rows), workstreams }; +} + +/** One contractor's assignments on the project. Empty when it has none. */ +export async function findContractorAssignments( + projectId: bigint, + organisationId: string, +): Promise { + const rows = await loadAssignmentRows(projectId, organisationId); + return groupByContractor(rows)[0]?.assignments ?? []; +} + +/** + * Search existing organisations by name for the "Add contractor" picker. + * + * Creating organisations is **out of scope** for this flow (the "invite + * company to Ara" flow owns it), so this only ever reads. Organisations with + * no name are skipped: they cannot be told apart in a picker, so offering them + * would be offering a choice the user cannot make. + */ +export async function searchOrganisations( + projectId: bigint, + query: string, + limit = 20, +): Promise { + // `%` and `_` are LIKE wildcards: a user typing them means the characters, + // not "match anything", so they are escaped rather than honoured. + const trimmed = query.trim().slice(0, 100).replace(/[\\%_]/g, "\\$&"); + + const [rows, assigned] = await Promise.all([ + db + .select({ id: organisation.id, name: organisation.name }) + .from(organisation) + .where( + trimmed + ? and( + isNotNull(organisation.name), + ne(organisation.name, ""), + ilike(organisation.name, `%${trimmed}%`), + ) + : and(isNotNull(organisation.name), ne(organisation.name, "")), + ) + .orderBy(organisation.name) + .limit(limit), + db + .selectDistinct({ + organisationId: projectWorkstreamContractor.organisationId, + }) + .from(projectWorkstreamContractor) + .innerJoin( + projectWorkstream, + eq( + projectWorkstreamContractor.projectWorkstreamId, + projectWorkstream.id, + ), + ) + .where(eq(projectWorkstream.projectId, projectId)), + ]); + + const assignedIds = new Set(assigned.map((row) => row.organisationId)); + + return rows.map((row) => ({ + id: row.id, + name: row.name ?? "Unnamed organisation", + alreadyAssigned: assignedIds.has(row.id), + })); +} + +/** True when `organisationId` is a real organisation. */ +export async function organisationExists( + organisationId: string, +): Promise { + const [found] = await db + .select({ id: organisation.id }) + .from(organisation) + .where(eq(organisation.id, organisationId)) + .limit(1); + return Boolean(found); +} + +/** + * How many contractors *other than* `organisationId` are assigned to each of + * `projectWorkstreamIds` — the "would this workstream be left with none?" + * fact `decideRemoval` judges on. Workstreams with no other contractor are + * absent from the record, which that function reads as zero. + */ +export async function countOtherContractors( + projectWorkstreamIds: bigint[], + organisationId: string, +): Promise> { + if (projectWorkstreamIds.length === 0) return {}; + + const rows = await db + .select({ + projectWorkstreamId: projectWorkstreamContractor.projectWorkstreamId, + contractors: sql`count(distinct ${projectWorkstreamContractor.organisationId})::int`, + }) + .from(projectWorkstreamContractor) + .where( + and( + inArray( + projectWorkstreamContractor.projectWorkstreamId, + projectWorkstreamIds, + ), + ne(projectWorkstreamContractor.organisationId, organisationId), + ), + ) + .groupBy(projectWorkstreamContractor.projectWorkstreamId); + + return Object.fromEntries( + rows.map((row) => [row.projectWorkstreamId.toString(), row.contractors]), + ); +} + +/** + * One workstream and the permissions it should carry — the unit the grid + * edits. Permissions travel per workstream, never as one pair for the whole + * contractor (ADR-0022). + */ +export interface DesiredAssignment { + projectWorkstreamId: bigint; + updateStagesPermission: boolean; + uploadDocumentsPermission: boolean; +} + +/** `"1-0"` — the flag pair, so rows sharing one can be updated together. */ +function flagKey(desired: DesiredAssignment): string { + return `${desired.updateStagesPermission ? 1 : 0}-${ + desired.uploadDocumentsPermission ? 1 : 0 + }`; +} + +/** + * Write one contractor's assignments on a project. + * + * `mode` decides what happens to the workstreams the request did *not* name: + * - `"merge"` (POST, add contractor) leaves them alone. + * - `"replace"` (PATCH, edit contractor) deletes them — the caller must have + * run `decideRemoval` over exactly those rows first. + * + * `project_workstream_contractor` carries no unique index on + * (project_workstream_id, organisation_id), so the read-then-write runs inside + * a transaction — the narrowest guard available without a migration, matching + * `selectWorkstream` in the workstream step. + * + * Updates are grouped by flag pair rather than issued per row: there are only + * four possible pairs, so a contractor on twenty workstreams still costs at + * most four UPDATEs. + * + * `assigned_at` is left to its column default, so a re-permissioned assignment + * keeps the timestamp it was first made at. + */ +export async function writeContractorAssignments( + projectId: bigint, + organisationId: string, + desired: DesiredAssignment[], + mode: "merge" | "replace", +): Promise<{ created: number; updated: number; removed: number }> { + return db.transaction(async (tx) => { + // Scoped to this project, not merely to the organisation: the same + // contractor may deliver workstreams on other projects, and a replace + // must never reach them. + const existing = await tx + .select({ + id: projectWorkstreamContractor.id, + projectWorkstreamId: projectWorkstreamContractor.projectWorkstreamId, + }) + .from(projectWorkstreamContractor) + .innerJoin( + projectWorkstream, + eq( + projectWorkstreamContractor.projectWorkstreamId, + projectWorkstream.id, + ), + ) + .where( + and( + eq(projectWorkstream.projectId, projectId), + eq(projectWorkstreamContractor.organisationId, organisationId), + ), + ); + + const wanted = new Map( + desired.map((row) => [row.projectWorkstreamId.toString(), row]), + ); + const held = new Map( + existing.map((row) => [row.projectWorkstreamId.toString(), row.id]), + ); + + const toCreate = desired.filter( + (row) => !held.has(row.projectWorkstreamId.toString()), + ); + + // Existing rows the request still wants, bucketed by the flag pair they + // should end up with. + const updateBuckets = new Map< + string, + { flags: DesiredAssignment; ids: bigint[] } + >(); + let updated = 0; + for (const row of existing) { + const target = wanted.get(row.projectWorkstreamId.toString()); + if (!target) continue; + const key = flagKey(target); + const bucket = updateBuckets.get(key) ?? { flags: target, ids: [] }; + bucket.ids.push(row.id); + updateBuckets.set(key, bucket); + updated += 1; + } + + if (toCreate.length > 0) { + await tx.insert(projectWorkstreamContractor).values( + toCreate.map((row) => ({ + projectWorkstreamId: row.projectWorkstreamId, + organisationId, + updateStagesPermission: row.updateStagesPermission, + uploadDocumentsPermission: row.uploadDocumentsPermission, + })), + ); + } + + for (const { flags, ids } of updateBuckets.values()) { + await tx + .update(projectWorkstreamContractor) + .set({ + updateStagesPermission: flags.updateStagesPermission, + uploadDocumentsPermission: flags.uploadDocumentsPermission, + }) + .where(inArray(projectWorkstreamContractor.id, ids)); + } + + let removed = 0; + if (mode === "replace") { + const stale = existing + .filter((row) => !wanted.has(row.projectWorkstreamId.toString())) + .map((row) => row.id); + + if (stale.length > 0) { + await tx + .delete(projectWorkstreamContractor) + .where(inArray(projectWorkstreamContractor.id, stale)); + removed = stale.length; + } + } + + return { created: toCreate.length, updated, removed }; + }); +} + +/** Delete specific assignments by id. Callers run `decideRemoval` first. */ +export async function deleteAssignments(ids: bigint[]): Promise { + if (ids.length === 0) return 0; + await db + .delete(projectWorkstreamContractor) + .where(inArray(projectWorkstreamContractor.id, ids)); + return ids.length; +} diff --git a/src/app/api/projects/[projectId]/contractors/route.test.ts b/src/app/api/projects/[projectId]/contractors/route.test.ts new file mode 100644 index 00000000..743a1ea8 --- /dev/null +++ b/src/app/api/projects/[projectId]/contractors/route.test.ts @@ -0,0 +1,355 @@ +/** + * GET / POST `/api/projects/[projectId]/contractors` (issue #413). + * + * The database is mocked at the module boundary (`./queries` and the authz + * repository); no connection is opened. The authorization *decisions* are the + * real ones from `@/lib/projects/authz` — only the facts they read are faked. + */ +import { describe, expect, it, beforeEach, vi } from "vitest"; +import { NextRequest } from "next/server"; + +const { + mockGetServerSession, + mockLoadAuthzUser, + mockLoadProjectAuthzFacts, + mockLoadContractorsView, + mockListProjectWorkstreams, + mockOrganisationExists, + mockWriteContractorAssignments, +} = vi.hoisted(() => ({ + mockGetServerSession: vi.fn(), + mockLoadAuthzUser: vi.fn(), + mockLoadProjectAuthzFacts: vi.fn(), + mockLoadContractorsView: vi.fn(), + mockListProjectWorkstreams: vi.fn(), + mockOrganisationExists: vi.fn(), + mockWriteContractorAssignments: vi.fn(), +})); + +vi.mock("next-auth", () => ({ getServerSession: mockGetServerSession })); +vi.mock("@/app/api/auth/[...nextauth]/authOptions", () => ({ AuthOptions: {} })); +vi.mock("@/app/repositories/projects/authzRepository", () => ({ + loadAuthzUser: mockLoadAuthzUser, + loadProjectAuthzFacts: mockLoadProjectAuthzFacts, +})); +vi.mock("./queries", () => ({ + loadContractorsView: mockLoadContractorsView, + listProjectWorkstreams: mockListProjectWorkstreams, + organisationExists: mockOrganisationExists, + writeContractorAssignments: mockWriteContractorAssignments, +})); + +import { GET, POST } from "./route"; + +const CLIENT_ORG = "11111111-1111-1111-1111-111111111111"; +const CONTRACTOR_ORG = "22222222-2222-2222-2222-222222222222"; +const OTHER_ORG = "33333333-3333-3333-3333-333333333333"; +const APEX = "44444444-4444-4444-4444-444444444444"; + +const WORKSTREAMS = [ + { projectWorkstreamId: "10", name: "Windows", contractorCount: 1 }, + { projectWorkstreamId: "11", name: "Roofs", contractorCount: 0 }, +]; + +function signedInAs(organisationIds: string[]) { + mockGetServerSession.mockResolvedValue({ user: { dbId: "7" } }); + mockLoadAuthzUser.mockResolvedValue({ + id: 7n, + email: "someone@landlord.example", + organisationIds, + }); +} + +function projectExists() { + mockLoadProjectAuthzFacts.mockResolvedValue({ + id: 5n, + organisationId: CLIENT_ORG, + domnaAdminAccess: false, + contractorOrganisationIds: [CONTRACTOR_ORG], + }); +} + +const params = { params: Promise.resolve({ projectId: "5" }) }; + +function postRequest(body: unknown) { + return new NextRequest("http://test/api/projects/5/contractors", { + method: "POST", + body: JSON.stringify(body), + }); +} + +function getRequest() { + return new NextRequest("http://test/api/projects/5/contractors"); +} + +/** One grid row: a workstream and the permissions it should carry. */ +function ws( + projectWorkstreamId: string, + updateStagesPermission = false, + uploadDocumentsPermission = false, +) { + return { + projectWorkstreamId, + updateStagesPermission, + uploadDocumentsPermission, + }; +} + +const VALID_BODY = { + organisationId: APEX, + assignments: [ws("10", true, false), ws("11", false, true)], +}; + +beforeEach(() => { + vi.clearAllMocks(); + mockLoadContractorsView.mockResolvedValue({ + contractors: [], + workstreams: WORKSTREAMS, + }); + mockListProjectWorkstreams.mockResolvedValue(WORKSTREAMS); + mockOrganisationExists.mockResolvedValue(true); + mockWriteContractorAssignments.mockResolvedValue({ + created: 2, + updated: 0, + removed: 0, + }); +}); + +describe("GET /api/projects/[projectId]/contractors", () => { + it("returns the table with canManage for the client organisation", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + + const res = await GET(getRequest(), params); + + expect(res.status).toBe(200); + await expect(res.json()).resolves.toEqual({ + contractors: [], + workstreams: WORKSTREAMS, + canManage: true, + }); + }); + + it("lets an assigned contractor read the table, but not manage it", async () => { + signedInAs([CONTRACTOR_ORG]); + projectExists(); + + const res = await GET(getRequest(), params); + + expect(res.status).toBe(200); + await expect(res.json()).resolves.toMatchObject({ canManage: false }); + }); + + it("404s a project the caller has no standing on", async () => { + signedInAs([OTHER_ORG]); + projectExists(); + + const res = await GET(getRequest(), params); + + expect(res.status).toBe(404); + expect(mockLoadContractorsView).not.toHaveBeenCalled(); + }); + + it("401s without a session", async () => { + mockGetServerSession.mockResolvedValue(null); + + const res = await GET(getRequest(), params); + + expect(res.status).toBe(401); + }); +}); + +describe("POST /api/projects/[projectId]/contractors", () => { + it("assigns the contractor to every named workstream", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + + const res = await POST(postRequest(VALID_BODY), params); + + expect(res.status).toBe(201); + expect(mockWriteContractorAssignments).toHaveBeenCalledWith( + 5n, + APEX, + [ + { + projectWorkstreamId: 10n, + updateStagesPermission: true, + uploadDocumentsPermission: false, + }, + { + projectWorkstreamId: 11n, + updateStagesPermission: false, + uploadDocumentsPermission: true, + }, + ], + "merge", + ); + }); + + it("returns 200 when the assignment already existed and was re-permissioned", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + mockWriteContractorAssignments.mockResolvedValue({ + created: 0, + updated: 2, + removed: 0, + }); + + const res = await POST(postRequest(VALID_BODY), params); + + expect(res.status).toBe(200); + await expect(res.json()).resolves.toMatchObject({ updated: 2 }); + }); + + it("defaults both permissions to off when the body omits them", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + + await POST( + postRequest({ + organisationId: APEX, + assignments: [{ projectWorkstreamId: "10" }], + }), + params, + ); + + expect(mockWriteContractorAssignments).toHaveBeenCalledWith( + 5n, + APEX, + [ + { + projectWorkstreamId: 10n, + updateStagesPermission: false, + uploadDocumentsPermission: false, + }, + ], + "merge", + ); + }); + + it("403s a contractor trying to assign another contractor", async () => { + signedInAs([CONTRACTOR_ORG]); + projectExists(); + + const res = await POST(postRequest(VALID_BODY), params); + + expect(res.status).toBe(403); + expect(mockWriteContractorAssignments).not.toHaveBeenCalled(); + }); + + it("rejects a body with no workstreams", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + + const res = await POST( + postRequest({ organisationId: APEX, assignments: [] }), + params, + ); + + expect(res.status).toBe(400); + await expect(res.json()).resolves.toEqual({ error: "Invalid body" }); + expect(mockWriteContractorAssignments).not.toHaveBeenCalled(); + }); + + it("rejects a workstream named twice — two answers to one question", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + + const res = await POST( + postRequest({ + organisationId: APEX, + assignments: [ws("10", true, true), ws("10", false, false)], + }), + params, + ); + + expect(res.status).toBe(400); + expect(mockWriteContractorAssignments).not.toHaveBeenCalled(); + }); + + it("carries different permissions per workstream through untouched", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + + await POST( + postRequest({ + organisationId: APEX, + assignments: [ws("10", true, false), ws("11", false, false)], + }), + params, + ); + + const [, , assignments] = mockWriteContractorAssignments.mock.calls[0]; + expect(assignments).toEqual([ + { + projectWorkstreamId: 10n, + updateStagesPermission: true, + uploadDocumentsPermission: false, + }, + { + projectWorkstreamId: 11n, + updateStagesPermission: false, + uploadDocumentsPermission: false, + }, + ]); + }); + + it("rejects an organisationId that is not a uuid", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + + const res = await POST( + postRequest({ organisationId: "apex", assignments: [ws("10")] }), + params, + ); + + expect(res.status).toBe(400); + }); + + it("404s an organisation that does not exist", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + mockOrganisationExists.mockResolvedValue(false); + + const res = await POST(postRequest(VALID_BODY), params); + + expect(res.status).toBe(404); + await expect(res.json()).resolves.toEqual({ + error: "Organisation not found", + }); + expect(mockWriteContractorAssignments).not.toHaveBeenCalled(); + }); + + it("404s a workstream belonging to a different project", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + + const res = await POST( + postRequest({ ...VALID_BODY, assignments: [ws("10"), ws("999")] }), + params, + ); + + expect(res.status).toBe(404); + await expect(res.json()).resolves.toEqual({ + error: "Workstream not found on this project", + }); + expect(mockWriteContractorAssignments).not.toHaveBeenCalled(); + }); + + it("500s, without leaking the error, when the write fails", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + mockWriteContractorAssignments.mockRejectedValue(new Error("pg exploded")); + const consoleError = vi + .spyOn(console, "error") + .mockImplementation(() => undefined); + + const res = await POST(postRequest(VALID_BODY), params); + + expect(res.status).toBe(500); + await expect(res.json()).resolves.toEqual({ + error: "Couldn't assign the contractor", + }); + consoleError.mockRestore(); + }); +}); diff --git a/src/app/api/projects/[projectId]/contractors/route.ts b/src/app/api/projects/[projectId]/contractors/route.ts new file mode 100644 index 00000000..00f62520 --- /dev/null +++ b/src/app/api/projects/[projectId]/contractors/route.ts @@ -0,0 +1,106 @@ +/** + * `/api/projects/[projectId]/contractors` (issue #413). + * + * GET — the permissions table: every contractor on the project, the + * workstreams each delivers, and their two permission flags. + * POST — add a contractor: one `project_workstream_contractor` row per chosen + * workstream. + * + * Editing and removing an existing contractor live on + * `[organisationId]/route.ts`, because their removal rules need to name a + * single contractor. + */ +import { NextRequest, NextResponse } from "next/server"; +import { authorizeContractorRequest } from "./authorize"; +import { + addContractorBodySchema, + type AddContractorBody, +} from "./validation"; +import { + listProjectWorkstreams, + loadContractorsView, + organisationExists, + writeContractorAssignments, +} from "./queries"; + +type Params = { params: Promise<{ projectId: string }> }; + +/** GET — the table's data, re-read from the database on every request. */ +export async function GET(_req: NextRequest, props: Params) { + const { projectId } = await props.params; + const auth = await authorizeContractorRequest(projectId, "view"); + if (!auth.ok) { + return NextResponse.json({ error: auth.error }, { status: auth.status }); + } + + const view = await loadContractorsView(auth.projectId); + return NextResponse.json({ ...view, canManage: auth.canManage }); +} + +/** + * POST — assign a contractor to one or more of the project's workstreams, each + * with its own permissions. + * + * Additive: workstreams the body does not name are left alone, so adding a + * second contractor never displaces the first (the schema allows several per + * workstream, and so does this). Re-posting a workstream the contractor + * already holds re-permissions it rather than duplicating the row. + */ +export async function POST(req: NextRequest, props: Params) { + const { projectId } = await props.params; + const auth = await authorizeContractorRequest(projectId, "manage"); + if (!auth.ok) { + return NextResponse.json({ error: auth.error }, { status: auth.status }); + } + + let body: AddContractorBody; + try { + body = addContractorBodySchema.parse(await req.json()); + } catch { + return NextResponse.json({ error: "Invalid body" }, { status: 400 }); + } + + if (!(await organisationExists(body.organisationId))) { + return NextResponse.json( + { error: "Organisation not found" }, + { status: 404 }, + ); + } + + // Every named workstream must belong to *this* project — otherwise a caller + // who may manage one project could assign contractors on another. + const owned = new Set( + (await listProjectWorkstreams(auth.projectId)).map( + (w) => w.projectWorkstreamId, + ), + ); + if (body.assignments.some((a) => !owned.has(a.projectWorkstreamId))) { + return NextResponse.json( + { error: "Workstream not found on this project" }, + { status: 404 }, + ); + } + + try { + const result = await writeContractorAssignments( + auth.projectId, + body.organisationId, + body.assignments.map((a) => ({ + projectWorkstreamId: BigInt(a.projectWorkstreamId), + updateStagesPermission: a.updateStagesPermission, + uploadDocumentsPermission: a.uploadDocumentsPermission, + })), + "merge", + ); + return NextResponse.json( + { organisationId: body.organisationId, ...result }, + { status: result.created > 0 ? 201 : 200 }, + ); + } catch (err) { + console.error("POST /api/projects/[projectId]/contractors failed:", err); + return NextResponse.json( + { error: "Couldn't assign the contractor" }, + { status: 500 }, + ); + } +} diff --git a/src/app/api/projects/[projectId]/contractors/validation.ts b/src/app/api/projects/[projectId]/contractors/validation.ts new file mode 100644 index 00000000..7520af2c --- /dev/null +++ b/src/app/api/projects/[projectId]/contractors/validation.ts @@ -0,0 +1,52 @@ +/** + * Request body shapes for the contractor endpoints (issue #413). + * + * They live outside the two `route.ts` files because both need the assignment + * body and an App Router route module may only export HTTP handlers and the + * route-config options — an exported schema there is a build error. + */ +import { z } from "zod"; + +/** + * One (workstream, permissions) triple — the unit the grid edits and the unit + * `project_workstream_contractor` stores. + * + * `project_workstream.id` arrives as a string: it is bigint in the database and + * does not survive JSON. Both flags default to false, matching the column + * defaults — an assignment grants nothing unless asked. + */ +export const assignmentSchema = z.object({ + projectWorkstreamId: z + .string() + .regex(/^\d+$/, "workstream ids must be numeric"), + updateStagesPermission: z.boolean().default(false), + uploadDocumentsPermission: z.boolean().default(false), +}); + +/** + * The assignment set a write asks for — permissions per workstream, never one + * pair applied to all of them (ADR-0022). + * + * A workstream may appear only once: two entries for the same workstream carry + * two answers to the same question, and picking one silently is worse than + * refusing. + */ +export const assignmentBodySchema = z.object({ + assignments: z + .array(assignmentSchema) + .min(1, "Choose at least one workstream") + .refine( + (rows) => + new Set(rows.map((r) => r.projectWorkstreamId)).size === rows.length, + { message: "Each workstream may appear only once" }, + ), +}); + +/** Adding a contractor also names which organisation is being assigned. */ +export const addContractorBodySchema = assignmentBodySchema.extend({ + organisationId: z.string().uuid("organisationId must be a uuid"), +}); + +export type AssignmentInput = z.infer; +export type AssignmentBody = z.infer; +export type AddContractorBody = z.infer; diff --git a/src/app/api/projects/[projectId]/import/parse/route.ts b/src/app/api/projects/[projectId]/import/parse/route.ts new file mode 100644 index 00000000..0f487888 --- /dev/null +++ b/src/app/api/projects/[projectId]/import/parse/route.ts @@ -0,0 +1,99 @@ +import { NextRequest, NextResponse } from "next/server"; +import { getServerSession } from "next-auth"; +import { AuthOptions } from "@/app/api/auth/[...nextauth]/authOptions"; +import { canManageProject } from "@/lib/projects/authz"; +import { + loadAuthzUser, + loadProjectAuthzFacts, +} from "@/app/repositories/projects/authzRepository"; +import { + hasAcceptedImportExtension, + MAX_IMPORT_FILE_BYTES, + parseImportFile, +} from "@/lib/projects/import/parse"; + +type Params = { params: Promise<{ projectId: string }> }; + +/** + * POST — parse an uploaded work-order import file (issue #414). + * + * Takes `multipart/form-data` with a single `file` field and returns the + * headers, every data row, a row count and a first-N preview. It writes + * nothing: the import is not persisted until commit (#417). + * + * The rows come back in full, not just the preview, because the parsed file is + * held client-side across the mapping and validation steps and POSTed once at + * commit — see the commit message for why that beat staging the file in S3. + */ +export async function POST(req: NextRequest, props: Params) { + const { projectId } = await props.params; + + const session = await getServerSession(AuthOptions); + if (!session?.user?.dbId) { + return NextResponse.json({ error: "Unauthorised" }, { status: 401 }); + } + if (!/^\d+$/.test(projectId)) { + return NextResponse.json({ error: "Invalid project id" }, { status: 400 }); + } + + const [user, project] = await Promise.all([ + loadAuthzUser(BigInt(session.user.dbId)), + loadProjectAuthzFacts(BigInt(projectId)), + ]); + // A project the caller cannot see must 404, not 403 — its existence is not + // theirs to learn (see `@/lib/projects/authz`). + if (!user || !project) { + return NextResponse.json({ error: "Project not found" }, { status: 404 }); + } + // Importing is managing: internal and client-org only, never a contractor. + if (!canManageProject(user, project)) { + return NextResponse.json({ error: "Forbidden" }, { status: 403 }); + } + + let form: FormData; + try { + form = await req.formData(); + } catch { + return NextResponse.json( + { error: "Expected a file upload" }, + { status: 400 }, + ); + } + + const file = form.get("file"); + if (!(file instanceof File)) { + return NextResponse.json({ error: "No file was uploaded" }, { status: 400 }); + } + if (!hasAcceptedImportExtension(file.name)) { + return NextResponse.json( + { error: "That file type isn't supported — upload a .csv, .xlsx or .xls file." }, + { status: 400 }, + ); + } + // Re-checked here even though the drop zone checks it too: the client-side + // limit is a courtesy, this one is the rule. + if (file.size > MAX_IMPORT_FILE_BYTES) { + return NextResponse.json( + { + error: `That file is larger than ${MAX_IMPORT_FILE_BYTES / (1024 * 1024)}MB — split it into smaller files.`, + }, + { status: 413 }, + ); + } + if (file.size === 0) { + return NextResponse.json({ error: "That file is empty." }, { status: 400 }); + } + + const result = parseImportFile(new Uint8Array(await file.arrayBuffer())); + if (!result.ok) { + return NextResponse.json({ error: result.error }, { status: 400 }); + } + + return NextResponse.json({ + filename: file.name, + headers: result.file.headers, + rows: result.file.rows, + rowCount: result.file.rowCount, + preview: result.file.preview, + }); +} diff --git a/src/app/api/projects/[projectId]/import/template/route.ts b/src/app/api/projects/[projectId]/import/template/route.ts new file mode 100644 index 00000000..3371555a --- /dev/null +++ b/src/app/api/projects/[projectId]/import/template/route.ts @@ -0,0 +1,56 @@ +import { NextRequest, NextResponse } from "next/server"; +import { getServerSession } from "next-auth"; +import { AuthOptions } from "@/app/api/auth/[...nextauth]/authOptions"; +import { canManageProject } from "@/lib/projects/authz"; +import { + loadAuthzUser, + loadProjectAuthzFacts, +} from "@/app/repositories/projects/authzRepository"; +import { buildImportTemplateCsv } from "@/lib/projects/import/parse"; + +type Params = { params: Promise<{ projectId: string }> }; + +/** + * GET — the "Download template" artefact: a CSV carrying the expected headings + * plus a worked example (issue #414). + * + * Served from a route handler rather than built in the browser so the template + * and the parser read their column list from the same constant — a heading + * renamed in one place cannot drift from the other. + * + * Gated behind the same permission as the import itself: the template is not + * secret, but there is no reason for it to be the one Projects endpoint a + * contractor can reach. + */ +export async function GET(_req: NextRequest, props: Params) { + const { projectId } = await props.params; + + const session = await getServerSession(AuthOptions); + if (!session?.user?.dbId) { + return NextResponse.json({ error: "Unauthorised" }, { status: 401 }); + } + if (!/^\d+$/.test(projectId)) { + return NextResponse.json({ error: "Invalid project id" }, { status: 400 }); + } + + const [user, project] = await Promise.all([ + loadAuthzUser(BigInt(session.user.dbId)), + loadProjectAuthzFacts(BigInt(projectId)), + ]); + if (!user || !project) { + return NextResponse.json({ error: "Project not found" }, { status: 404 }); + } + if (!canManageProject(user, project)) { + return NextResponse.json({ error: "Forbidden" }, { status: 403 }); + } + + // BOM so Excel opens the CSV as UTF-8 rather than guessing a codepage. + return new NextResponse(`${buildImportTemplateCsv()}`, { + headers: { + "Content-Type": "text/csv; charset=utf-8", + "Content-Disposition": + 'attachment; filename="work-order-import-template.csv"', + "Cache-Control": "no-store", + }, + }); +} diff --git a/src/app/api/projects/[projectId]/route.ts b/src/app/api/projects/[projectId]/route.ts new file mode 100644 index 00000000..9762018f --- /dev/null +++ b/src/app/api/projects/[projectId]/route.ts @@ -0,0 +1,99 @@ +import { NextRequest, NextResponse } from "next/server"; +import { getServerSession } from "next-auth"; +import { AuthOptions } from "@/app/api/auth/[...nextauth]/authOptions"; +import { canManageProject, canViewProject } from "@/lib/projects/authz"; +import { + projectFactsAfterUpdate, + updateProjectSchema, +} from "@/lib/projects/updateProject"; +import { parseProjectId } from "@/app/projects/guards"; +import { + loadAuthzUserByEmail, + loadProjectAuthzFacts, +} from "@/app/repositories/projects/authzRepository"; +import { projectTypeExists } from "@/app/repositories/projects/projectsRepository"; +import { updateProjectDetails } from "@/app/repositories/projects/projectSettingsRepository"; + +/** + * PATCH /api/projects/[projectId] — edit a project's details from the settings + * hub (issue #444). + * + * Authorization is the existing rule, asked twice: + * + * 1. **May this user manage this project?** — `canManageProject` against the + * stored facts. A user who cannot even *view* the project gets a 404 rather + * than a 403, because project existence must not leak outside its + * organisation; a contractor, who legitimately knows the project exists, + * gets an honest 403. + * 2. **Would they still manage it afterwards?** — `canManageProject` against + * `projectFactsAfterUpdate`. Un-ticking `domna_admin_access` revokes the + * `internal` role, so an internal non-member could otherwise save an edit + * that instantly locks them out of the project with no way back. This is + * the same guard `POST /api/projects` applies to creation, for the same + * reason — no separate "may this edit be made?" rule exists. + * + * The owning organisation is never read from the request body: it is not part + * of `updateProjectSchema`, and the update statement does not touch the column. + */ +export async function PATCH( + req: NextRequest, + props: { params: Promise<{ projectId: string }> }, +) { + const { projectId } = await props.params; + + const session = await getServerSession(AuthOptions); + if (!session?.user?.email) { + return NextResponse.json({ error: "Unauthorised" }, { status: 401 }); + } + + const user = await loadAuthzUserByEmail(session.user.email); + if (!user) { + return NextResponse.json({ error: "Unauthorised" }, { status: 401 }); + } + + const id = parseProjectId(projectId); + if (id === null) { + return NextResponse.json({ error: "Project not found" }, { status: 404 }); + } + + const project = await loadProjectAuthzFacts(id); + if (!project || !canViewProject(user, project)) { + return NextResponse.json({ error: "Project not found" }, { status: 404 }); + } + if (!canManageProject(user, project)) { + return NextResponse.json( + { error: "You cannot change this project's settings" }, + { status: 403 }, + ); + } + + const parsed = updateProjectSchema.safeParse( + await req.json().catch(() => null), + ); + if (!parsed.success) { + return NextResponse.json( + { error: parsed.error.issues[0]?.message ?? "Invalid body" }, + { status: 400 }, + ); + } + const draft = parsed.data; + + if (!canManageProject(user, projectFactsAfterUpdate(project, draft))) { + return NextResponse.json( + { + error: + "Removing Domna admin access would lock you out of this project. Ask a member of the client organisation to make that change.", + }, + { status: 403 }, + ); + } + + const projectTypeId = BigInt(draft.projectTypeId); + if (!(await projectTypeExists(projectTypeId))) { + return NextResponse.json({ error: "Unknown project type" }, { status: 400 }); + } + + await updateProjectDetails(id, { ...draft, projectTypeId }); + + return NextResponse.json({ id: id.toString() }, { status: 200 }); +} diff --git a/src/app/api/projects/[projectId]/sharepoint/queries.ts b/src/app/api/projects/[projectId]/sharepoint/queries.ts new file mode 100644 index 00000000..f20d5799 --- /dev/null +++ b/src/app/api/projects/[projectId]/sharepoint/queries.ts @@ -0,0 +1,49 @@ +/** + * Persistence for the two project-level SharePoint columns (issue #412). + * + * Deliberately narrow: it reads and writes `sharepoint_base_url` and + * `sharepoint_sub_folder_template` and touches no other column of `project`, so + * this screen can never disturb the details the settings hub owns (#444). + */ +import { db } from "@/app/db/db"; +import { eq } from "drizzle-orm"; +import { project } from "@/app/db/schema/projects/projects"; +import type { + SharepointSettings, + SharepointSettingsDraft, +} from "@/lib/projects/sharepointSettings"; + +/** The stored fields, or null when the id names no project row. */ +export async function loadSharepointSettings( + projectId: bigint, +): Promise { + const [row] = await db + .select({ + sharepointBaseUrl: project.sharepointBaseUrl, + sharepointSubFolderTemplate: project.sharepointSubFolderTemplate, + }) + .from(project) + .where(eq(project.id, projectId)) + .limit(1); + return row ?? null; +} + +/** + * Write both fields. + * + * Absent values are written as explicit `null` rather than omitted, so clearing + * a field in the form actually clears the column — an omitted key would leave + * the old value in place, which reads back as the edit having silently failed. + */ +export async function updateSharepointSettings( + projectId: bigint, + draft: SharepointSettingsDraft, +): Promise { + await db + .update(project) + .set({ + sharepointBaseUrl: draft.sharepointBaseUrl ?? null, + sharepointSubFolderTemplate: draft.sharepointSubFolderTemplate ?? null, + }) + .where(eq(project.id, projectId)); +} diff --git a/src/app/api/projects/[projectId]/sharepoint/route.test.ts b/src/app/api/projects/[projectId]/sharepoint/route.test.ts new file mode 100644 index 00000000..95590d1f --- /dev/null +++ b/src/app/api/projects/[projectId]/sharepoint/route.test.ts @@ -0,0 +1,162 @@ +/** + * GET / PATCH `/api/projects/[projectId]/sharepoint` (issue #412). + * + * The database is mocked at the module boundary (`./queries` and the authz + * repository); no connection is opened. The authorization *decisions* are the + * real ones from `@/lib/projects/authz` — only the facts they read are faked. + */ +import { describe, expect, it, beforeEach, vi } from "vitest"; +import { NextRequest } from "next/server"; + +const { + mockGetServerSession, + mockLoadAuthzUser, + mockLoadProjectAuthzFacts, + mockLoadSharepointSettings, + mockUpdateSharepointSettings, +} = vi.hoisted(() => ({ + mockGetServerSession: vi.fn(), + mockLoadAuthzUser: vi.fn(), + mockLoadProjectAuthzFacts: vi.fn(), + mockLoadSharepointSettings: vi.fn(), + mockUpdateSharepointSettings: vi.fn(), +})); + +vi.mock("next-auth", () => ({ getServerSession: mockGetServerSession })); +vi.mock("@/app/api/auth/[...nextauth]/authOptions", () => ({ AuthOptions: {} })); +vi.mock("@/app/repositories/projects/authzRepository", () => ({ + loadAuthzUser: mockLoadAuthzUser, + loadProjectAuthzFacts: mockLoadProjectAuthzFacts, +})); +vi.mock("./queries", () => ({ + loadSharepointSettings: mockLoadSharepointSettings, + updateSharepointSettings: mockUpdateSharepointSettings, +})); + +import { GET, PATCH } from "./route"; + +const CLIENT_ORG = "11111111-1111-1111-1111-111111111111"; +const CONTRACTOR_ORG = "22222222-2222-2222-2222-222222222222"; + +const STORED = { + sharepointBaseUrl: "https://example.sharepoint.com/sites/works", + sharepointSubFolderTemplate: "/[AssetRef]/[WORef]", +}; + +function signedInAs(organisationIds: string[]) { + mockGetServerSession.mockResolvedValue({ user: { dbId: "7" } }); + mockLoadAuthzUser.mockResolvedValue({ + id: 7n, + email: "someone@landlord.example", + organisationIds, + }); +} + +function projectExists() { + mockLoadProjectAuthzFacts.mockResolvedValue({ + id: 5n, + organisationId: CLIENT_ORG, + domnaAdminAccess: false, + contractorOrganisationIds: [CONTRACTOR_ORG], + }); +} + +const params = () => ({ params: Promise.resolve({ projectId: "5" }) }); +const url = "http://localhost/api/projects/5/sharepoint"; + +const patchRequest = (body: unknown) => + new NextRequest(url, { + method: "PATCH", + body: JSON.stringify(body), + headers: { "content-type": "application/json" }, + }); + +beforeEach(() => { + vi.clearAllMocks(); + mockLoadSharepointSettings.mockResolvedValue(STORED); + mockUpdateSharepointSettings.mockResolvedValue(undefined); +}); + +describe("GET", () => { + it("401s without a session", async () => { + mockGetServerSession.mockResolvedValue(null); + const res = await GET(new NextRequest(url), params()); + expect(res.status).toBe(401); + }); + + it("returns the stored fields", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + const res = await GET(new NextRequest(url), params()); + expect(res.status).toBe(200); + expect(await res.json()).toEqual({ settings: STORED, canManage: true }); + }); +}); + +describe("PATCH", () => { + it("403s for a contractor", async () => { + signedInAs([CONTRACTOR_ORG]); + projectExists(); + const res = await PATCH(patchRequest(STORED), params()); + expect(res.status).toBe(403); + expect(mockUpdateSharepointSettings).not.toHaveBeenCalled(); + }); + + it("400s on a base URL that is not a full URL", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + const res = await PATCH( + patchRequest({ sharepointBaseUrl: "example.sharepoint.com/sites/works" }), + params(), + ); + expect(res.status).toBe(400); + expect(await res.json()).toEqual({ + error: "Enter a full URL, including https://", + }); + expect(mockUpdateSharepointSettings).not.toHaveBeenCalled(); + }); + + it("stores both fields", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + const res = await PATCH(patchRequest(STORED), params()); + expect(res.status).toBe(200); + expect(mockUpdateSharepointSettings).toHaveBeenCalledWith(5n, { + sharepointBaseUrl: STORED.sharepointBaseUrl, + sharepointSubFolderTemplate: STORED.sharepointSubFolderTemplate, + }); + }); + + it("clears a field the user emptied", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + const res = await PATCH( + patchRequest({ sharepointBaseUrl: "", sharepointSubFolderTemplate: "" }), + params(), + ); + expect(res.status).toBe(200); + expect(await res.json()).toEqual({ + settings: { + sharepointBaseUrl: null, + sharepointSubFolderTemplate: null, + }, + }); + expect(mockUpdateSharepointSettings).toHaveBeenCalledWith(5n, { + sharepointBaseUrl: undefined, + sharepointSubFolderTemplate: undefined, + }); + }); + + it("500s without leaking the driver error", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + const consoleError = vi.spyOn(console, "error").mockImplementation(() => {}); + mockUpdateSharepointSettings.mockRejectedValue(new Error("connection reset")); + const res = await PATCH(patchRequest(STORED), params()); + expect(res.status).toBe(500); + expect(await res.json()).toEqual({ + error: "Couldn't save the SharePoint settings", + }); + consoleError.mockRestore(); + }); +}); diff --git a/src/app/api/projects/[projectId]/sharepoint/route.ts b/src/app/api/projects/[projectId]/sharepoint/route.ts new file mode 100644 index 00000000..d51d1b29 --- /dev/null +++ b/src/app/api/projects/[projectId]/sharepoint/route.ts @@ -0,0 +1,71 @@ +/** + * `PATCH /api/projects/[projectId]/sharepoint` (issue #412). + * + * Stores the two project-level SharePoint fields the evidence-checklist screen + * collects. See `@/lib/projects/sharepointSettings` for why they are edited + * here rather than through the settings hub's details form, and for the fact + * that v1 **stores** them and syncs nothing (#429 owns sync). + * + * Authorization reuses `authorizeWorkstreamRequest` (#410) rather than restating + * the rule: despite the name, it is the project-level guard every endpoint under + * `/api/projects/[projectId]/…` in this module asks — 401 unauthenticated, 404 + * for a project the caller cannot see (existence must not leak outside its + * organisation) and 403 for a viewer who may not manage it. + */ +import { NextRequest, NextResponse } from "next/server"; +import { authorizeWorkstreamRequest } from "../workstreams/authorize"; +import { sharepointSettingsSchema } from "@/lib/projects/sharepointSettings"; +import { loadSharepointSettings, updateSharepointSettings } from "./queries"; + +type Params = { params: Promise<{ projectId: string }> }; + +/** GET — the stored fields, for a client that wants to re-read them. */ +export async function GET(_req: NextRequest, props: Params) { + const { projectId } = await props.params; + const auth = await authorizeWorkstreamRequest(projectId, "view"); + if (!auth.ok) { + return NextResponse.json({ error: auth.error }, { status: auth.status }); + } + + const settings = await loadSharepointSettings(auth.projectId); + if (!settings) { + return NextResponse.json({ error: "Project not found" }, { status: 404 }); + } + return NextResponse.json({ settings, canManage: auth.canManage }); +} + +export async function PATCH(req: NextRequest, props: Params) { + const { projectId } = await props.params; + const auth = await authorizeWorkstreamRequest(projectId, "manage"); + if (!auth.ok) { + return NextResponse.json({ error: auth.error }, { status: auth.status }); + } + + const parsed = sharepointSettingsSchema.safeParse( + await req.json().catch(() => null), + ); + if (!parsed.success) { + return NextResponse.json( + { error: parsed.error.issues[0]?.message ?? "Invalid body" }, + { status: 400 }, + ); + } + + try { + await updateSharepointSettings(auth.projectId, parsed.data); + } catch (err) { + console.error("PATCH /api/projects/[projectId]/sharepoint failed:", err); + return NextResponse.json( + { error: "Couldn't save the SharePoint settings" }, + { status: 500 }, + ); + } + + return NextResponse.json({ + settings: { + sharepointBaseUrl: parsed.data.sharepointBaseUrl ?? null, + sharepointSubFolderTemplate: + parsed.data.sharepointSubFolderTemplate ?? null, + }, + }); +} diff --git a/src/app/api/projects/[projectId]/work-orders/authorize.ts b/src/app/api/projects/[projectId]/work-orders/authorize.ts new file mode 100644 index 00000000..29f5ead4 --- /dev/null +++ b/src/app/api/projects/[projectId]/work-orders/authorize.ts @@ -0,0 +1,63 @@ +/** + * Request authorization for the work-orders endpoint (issue #419). + * + * Wiring only, mirroring `../workstreams/authorize.ts`: the session comes from + * NextAuth, the facts from the projects authz repository, and every *decision* + * from `@/lib/projects/authz` (#408). No permission rule is re-implemented here. + * + * A project the caller cannot see is reported as 404, never 403, so project + * existence does not leak outside its organisation. + * + * Scoping note: this endpoint is the **admin** table — internal and client-org + * members, per the issue's acceptance criteria — so it requires + * `canManageProject`. A contractor resolves a role on the project and would + * pass `canViewProject`, but must not see other contractors' work orders; + * narrowing the rows to their own assignments is a later issue, and until it + * lands the honest answer for a contractor is 403 rather than a table showing + * them the whole programme. + */ +import { getServerSession } from "next-auth"; +import { AuthOptions } from "@/app/api/auth/[...nextauth]/authOptions"; +import { + loadAuthzUser, + loadProjectAuthzFacts, +} from "@/app/repositories/projects/authzRepository"; +import { canManageProject, canViewProject } from "@/lib/projects/authz"; + +export type AuthorizeFailure = { error: string; status: 400 | 401 | 403 | 404 }; + +export type AuthorizeResult = + | { ok: true; projectId: bigint } + | ({ ok: false } & AuthorizeFailure); + +/** Resolve the caller's standing on `projectIdParam` for the admin table. */ +export async function authorizeWorkOrdersRequest( + projectIdParam: string, +): Promise { + const session = await getServerSession(AuthOptions); + if (!session?.user?.dbId) { + return { ok: false, error: "Unauthorised", status: 401 }; + } + + if (!/^\d+$/.test(projectIdParam)) { + return { ok: false, error: "Invalid project", status: 400 }; + } + const projectId = BigInt(projectIdParam); + + const [user, project] = await Promise.all([ + loadAuthzUser(BigInt(session.user.dbId)), + loadProjectAuthzFacts(projectId), + ]); + + if (!user) return { ok: false, error: "Unauthorised", status: 401 }; + if (!project) return { ok: false, error: "Project not found", status: 404 }; + + if (!canViewProject(user, project)) { + return { ok: false, error: "Project not found", status: 404 }; + } + if (!canManageProject(user, project)) { + return { ok: false, error: "Forbidden", status: 403 }; + } + + return { ok: true, projectId }; +} diff --git a/src/app/api/projects/[projectId]/work-orders/filters.test.ts b/src/app/api/projects/[projectId]/work-orders/filters.test.ts new file mode 100644 index 00000000..f9e63775 --- /dev/null +++ b/src/app/api/projects/[projectId]/work-orders/filters.test.ts @@ -0,0 +1,194 @@ +/** + * The work-orders query string (issue #419). + * + * Pure module, pure test: no database, no network. The round trip matters most + * — the client builds the params and the server parses them, so anything that + * survives `workOrderSearchParams` must come back out of `parseWorkOrderQuery` + * unchanged, or the table and its filter bar silently disagree. + */ +import { describe, expect, it } from "vitest"; +import { + DEFAULT_PAGE_SIZE, + MAX_PAGE_SIZE, + NO_FILTERS, + hasActiveFilters, + parseWorkOrderQuery, + withWorkstreamFilter, + workOrderSearchParams, + type WorkOrderFilterSelection, +} from "./filters"; + +const CONTRACTOR = "22222222-2222-2222-2222-222222222222"; + +const parse = (query: string) => parseWorkOrderQuery(new URLSearchParams(query)); + +describe("parseWorkOrderQuery", () => { + it("treats an empty query string as no filters and the default page size", () => { + const result = parse(""); + expect(result).toEqual({ + ok: true, + query: { + workstreamId: null, + contractorOrganisationId: null, + stageId: null, + overdueOnly: false, + missingEvidence: false, + cursor: null, + limit: DEFAULT_PAGE_SIZE, + }, + }); + }); + + it("parses every filter at once — they compose rather than override", () => { + const result = parse( + `workstreamId=10&stageId=102&contractorOrganisationId=${CONTRACTOR}` + + "&overdue=true&missingEvidence=true&cursor=812&limit=25", + ); + expect(result).toEqual({ + ok: true, + query: { + workstreamId: 10n, + contractorOrganisationId: CONTRACTOR, + stageId: 102n, + overdueOnly: true, + missingEvidence: true, + cursor: 812n, + limit: 25, + }, + }); + }); + + it("rejects a non-numeric id rather than silently dropping the filter", () => { + // A dropped filter shows a table that does not match the controls above it. + expect(parse("workstreamId=windows")).toEqual({ + ok: false, + error: "Invalid workstreamId", + }); + expect(parse("stageId=-1")).toEqual({ ok: false, error: "Invalid stageId" }); + expect(parse("cursor=0")).toEqual({ ok: false, error: "Invalid cursor" }); + }); + + it("rejects a contractor id that is not a uuid", () => { + expect(parse("contractorOrganisationId=42")).toEqual({ + ok: false, + error: "Invalid contractorOrganisationId", + }); + }); + + it("rejects a boolean it does not recognise, to catch a typo'd flag", () => { + expect(parse("overdue=yes")).toEqual({ ok: false, error: "Invalid overdue" }); + expect(parse("missingEvidence=on")).toEqual({ + ok: false, + error: "Invalid missingEvidence", + }); + }); + + it("accepts the falsey spellings of a flag", () => { + expect(parse("overdue=false")).toMatchObject({ + ok: true, + query: { overdueOnly: false }, + }); + expect(parse("overdue=1")).toMatchObject({ + ok: true, + query: { overdueOnly: true }, + }); + }); + + it("refuses to stream the whole programme in one response", () => { + expect(parse(`limit=${MAX_PAGE_SIZE}`)).toMatchObject({ ok: true }); + expect(parse(`limit=${MAX_PAGE_SIZE + 1}`)).toEqual({ + ok: false, + error: "Invalid limit", + }); + expect(parse("limit=0")).toEqual({ ok: false, error: "Invalid limit" }); + }); + + it("rejects a SQL fragment in an id parameter", () => { + expect(parse("workstreamId=1%3B+DROP+TABLE+work_order")).toEqual({ + ok: false, + error: "Invalid workstreamId", + }); + }); +}); + +describe("workOrderSearchParams", () => { + const selection: WorkOrderFilterSelection = { + workstreamId: "10", + contractorOrganisationId: CONTRACTOR, + stageId: "102", + overdueOnly: true, + missingEvidence: true, + }; + + it("round-trips a full selection back through the parser", () => { + const params = workOrderSearchParams(selection, { cursor: "812", limit: 25 }); + expect(parseWorkOrderQuery(params)).toEqual({ + ok: true, + query: { + workstreamId: 10n, + contractorOrganisationId: CONTRACTOR, + stageId: 102n, + overdueOnly: true, + missingEvidence: true, + cursor: 812n, + limit: 25, + }, + }); + }); + + it("omits everything falsey, so the unfiltered page has a stable cache key", () => { + expect(workOrderSearchParams(NO_FILTERS).toString()).toBe(""); + expect(workOrderSearchParams(NO_FILTERS, { cursor: null }).toString()).toBe(""); + }); +}); + +describe("withWorkstreamFilter", () => { + const STAGES = [ + { id: "101", workstreamId: "10" }, + { id: "201", workstreamId: "20" }, + ]; + + it("drops a stage that belongs to a different workstream", () => { + const next = withWorkstreamFilter( + { ...NO_FILTERS, stageId: "101" }, + STAGES, + "20", + ); + expect(next).toMatchObject({ workstreamId: "20", stageId: null }); + }); + + it("keeps a stage that belongs to the workstream being selected", () => { + const next = withWorkstreamFilter( + { ...NO_FILTERS, stageId: "101" }, + STAGES, + "10", + ); + expect(next).toMatchObject({ workstreamId: "10", stageId: "101" }); + }); + + it("keeps the stage when the workstream filter is cleared", () => { + const next = withWorkstreamFilter( + { ...NO_FILTERS, stageId: "101" }, + STAGES, + null, + ); + expect(next).toMatchObject({ workstreamId: null, stageId: "101" }); + }); + + it("leaves the other filters alone", () => { + const next = withWorkstreamFilter( + { ...NO_FILTERS, overdueOnly: true, missingEvidence: true }, + STAGES, + "20", + ); + expect(next).toMatchObject({ overdueOnly: true, missingEvidence: true }); + }); +}); + +describe("hasActiveFilters", () => { + it("is false only when nothing at all is narrowed", () => { + expect(hasActiveFilters(NO_FILTERS)).toBe(false); + expect(hasActiveFilters({ ...NO_FILTERS, overdueOnly: true })).toBe(true); + expect(hasActiveFilters({ ...NO_FILTERS, stageId: "1" })).toBe(true); + }); +}); diff --git a/src/app/api/projects/[projectId]/work-orders/filters.ts b/src/app/api/projects/[projectId]/work-orders/filters.ts new file mode 100644 index 00000000..afc8366d --- /dev/null +++ b/src/app/api/projects/[projectId]/work-orders/filters.ts @@ -0,0 +1,243 @@ +/** + * The work-orders table's query string, in one place (issue #419). + * + * The filter bar, the `useQuery` key, the fetch URL and the route handler all + * have to agree on exactly what `?overdue=true&cursor=812` means. They agree + * because they all go through this module: the client *builds* the search + * params with `workOrderSearchParams`, the handler *parses* them back with + * `parseWorkOrderQuery`, and neither reads a raw parameter name of its own. + * + * Pure by construction — no database client, no React — so it is safe to import + * from a client component and it unit-tests without a connection. + * + * ## Two representations, deliberately + * + * - **Selection** (`WorkOrderFilterSelection`) is what the UI holds: ids as + * strings, because bigint ids do not survive JSON and a `` sends. + */ +const stageId = z.union([idString, z.literal(""), z.null()]).transform((v) => (v ? v : null)); + +/** + * The naming rule is a display-only hint — a convention shown next to the + * requirement, never enforced against an uploaded file's name (#412 tasks). + */ +const namingRule = z + .union([z.string(), z.null()]) + .transform((v) => (v === null ? null : v.trim())) + .refine((v) => v === null || v.length <= 200, { + message: "Naming rule must be 200 characters or fewer", + }) + .transform((v) => (v ? v : null)); + +export const createRequirementSchema = z.object({ + fileType: z.enum(FILE_TYPE_VALUES, { + errorMap: () => ({ message: "Unknown document type" }), + }), + projectWorkstreamStageId: stageId.optional().default(null), + required: z.boolean().optional().default(true), + namingRule: namingRule.optional().default(null), +}); + +export type CreateRequirementBody = z.output; + +/** + * An edit to one row. Every field is optional and only the keys actually + * present are written, so the table's three independent controls (stage tag, + * required toggle, naming rule) can each save on their own without the other + * two riding along and clobbering a concurrent edit. + */ +export const updateRequirementSchema = z + .object({ + fileType: z.enum(FILE_TYPE_VALUES, { + errorMap: () => ({ message: "Unknown document type" }), + }), + projectWorkstreamStageId: stageId, + required: z.boolean(), + namingRule, + }) + .partial() + .refine((body) => Object.keys(body).length > 0, { + message: "Nothing to update", + }); + +export type UpdateRequirementBody = z.output; diff --git a/src/app/api/projects/[projectId]/workstreams/[workstreamId]/route.test.ts b/src/app/api/projects/[projectId]/workstreams/[workstreamId]/route.test.ts new file mode 100644 index 00000000..b1b20497 --- /dev/null +++ b/src/app/api/projects/[projectId]/workstreams/[workstreamId]/route.test.ts @@ -0,0 +1,184 @@ +/** + * DELETE `/api/projects/[projectId]/workstreams/[workstreamId]` (issue #410) — + * the deselect-with-dependents path. + * + * The database is mocked at the module boundary; no connection is opened. The + * cascade rules under test are the real ones from `../cascade`. + */ +import { describe, expect, it, beforeEach, vi } from "vitest"; +import { NextRequest } from "next/server"; +import { NO_DEPENDENTS, type WorkstreamDependents } from "../cascade"; + +const { + mockGetServerSession, + mockLoadAuthzUser, + mockLoadProjectAuthzFacts, + mockFindSelection, + mockDeselectWorkstream, +} = vi.hoisted(() => ({ + mockGetServerSession: vi.fn(), + mockLoadAuthzUser: vi.fn(), + mockLoadProjectAuthzFacts: vi.fn(), + mockFindSelection: vi.fn(), + mockDeselectWorkstream: vi.fn(), +})); + +vi.mock("next-auth", () => ({ getServerSession: mockGetServerSession })); +vi.mock("@/app/api/auth/[...nextauth]/authOptions", () => ({ AuthOptions: {} })); +vi.mock("@/app/repositories/projects/authzRepository", () => ({ + loadAuthzUser: mockLoadAuthzUser, + loadProjectAuthzFacts: mockLoadProjectAuthzFacts, +})); +vi.mock("../queries", () => ({ + findSelection: mockFindSelection, + deselectWorkstream: mockDeselectWorkstream, +})); + +import { DELETE } from "./route"; + +const CLIENT_ORG = "11111111-1111-1111-1111-111111111111"; +const CONTRACTOR_ORG = "22222222-2222-2222-2222-222222222222"; + +function signedInAs(organisationIds: string[]) { + mockGetServerSession.mockResolvedValue({ user: { dbId: "7" } }); + mockLoadAuthzUser.mockResolvedValue({ + id: 7n, + email: "someone@landlord.example", + organisationIds, + }); + mockLoadProjectAuthzFacts.mockResolvedValue({ + id: 5n, + organisationId: CLIENT_ORG, + domnaAdminAccess: false, + contractorOrganisationIds: [CONTRACTOR_ORG], + }); +} + +function selectionWith(dependents: Partial) { + mockFindSelection.mockResolvedValue({ + id: 9n, + dependents: { ...NO_DEPENDENTS, ...dependents }, + }); +} + +function request({ + confirm = false, + projectId = "5", + workstreamId = "1", +}: { confirm?: boolean; projectId?: string; workstreamId?: string } = {}) { + const url = `http://localhost/api/projects/${projectId}/workstreams/${workstreamId}${ + confirm ? "?confirm=true" : "" + }`; + return { + req: new NextRequest(url, { method: "DELETE" }), + props: { params: Promise.resolve({ projectId, workstreamId }) }, + }; +} + +beforeEach(() => { + vi.clearAllMocks(); + mockDeselectWorkstream.mockResolvedValue(undefined); + selectionWith({}); +}); + +describe("DELETE", () => { + it("401s without a session", async () => { + mockGetServerSession.mockResolvedValue(null); + const { req, props } = request(); + const res = await DELETE(req, props); + expect(res.status).toBe(401); + }); + + it("403s for a contractor", async () => { + signedInAs([CONTRACTOR_ORG]); + const { req, props } = request(); + const res = await DELETE(req, props); + expect(res.status).toBe(403); + expect(mockDeselectWorkstream).not.toHaveBeenCalled(); + }); + + it("400s on a non-numeric workstream id", async () => { + signedInAs([CLIENT_ORG]); + const { req, props } = request({ workstreamId: "windows" }); + const res = await DELETE(req, props); + expect(res.status).toBe(400); + expect(await res.json()).toEqual({ error: "Invalid workstream" }); + }); + + it("404s when the workstream is not selected on the project", async () => { + signedInAs([CLIENT_ORG]); + mockFindSelection.mockResolvedValue(null); + const { req, props } = request(); + const res = await DELETE(req, props); + expect(res.status).toBe(404); + expect(mockDeselectWorkstream).not.toHaveBeenCalled(); + }); + + it("deselects a workstream nothing hangs off", async () => { + signedInAs([CLIENT_ORG]); + const { req, props } = request(); + const res = await DELETE(req, props); + expect(res.status).toBe(200); + expect(await res.json()).toEqual({ workstreamId: "1", selected: false }); + expect(mockDeselectWorkstream).toHaveBeenCalledWith(9n); + }); + + it("409s asking for confirmation when configuration exists", async () => { + signedInAs([CLIENT_ORG]); + selectionWith({ stages: 5, contractors: 1 }); + const { req, props } = request(); + const res = await DELETE(req, props); + expect(res.status).toBe(409); + const body = await res.json(); + expect(body).toMatchObject({ + requiresConfirmation: true, + dependents: { stages: 5, contractors: 1 }, + }); + expect(body.error).toContain("5 stages and 1 contractor assignment"); + expect(mockDeselectWorkstream).not.toHaveBeenCalled(); + }); + + it("deselects once the caller confirms", async () => { + signedInAs([CLIENT_ORG]); + selectionWith({ stages: 5, evidenceRequirements: 2, contractors: 1 }); + const { req, props } = request({ confirm: true }); + const res = await DELETE(req, props); + expect(res.status).toBe(200); + expect(mockDeselectWorkstream).toHaveBeenCalledWith(9n); + }); + + it("409s blocked when work orders exist", async () => { + signedInAs([CLIENT_ORG]); + selectionWith({ stages: 5, workOrders: 3 }); + const { req, props } = request(); + const res = await DELETE(req, props); + expect(res.status).toBe(409); + const body = await res.json(); + expect(body).toMatchObject({ blocked: true, dependents: { workOrders: 3 } }); + expect(body.requiresConfirmation).toBeUndefined(); + expect(mockDeselectWorkstream).not.toHaveBeenCalled(); + }); + + it("stays blocked when the caller confirms anyway", async () => { + signedInAs([CLIENT_ORG]); + selectionWith({ workOrders: 1 }); + const { req, props } = request({ confirm: true }); + const res = await DELETE(req, props); + expect(res.status).toBe(409); + expect(await res.json()).toMatchObject({ blocked: true }); + expect(mockDeselectWorkstream).not.toHaveBeenCalled(); + }); + + it("500s without leaking the driver error", async () => { + signedInAs([CLIENT_ORG]); + const consoleError = vi.spyOn(console, "error").mockImplementation(() => {}); + mockDeselectWorkstream.mockRejectedValue(new Error("deadlock detected")); + const { req, props } = request(); + const res = await DELETE(req, props); + expect(res.status).toBe(500); + expect(await res.json()).toEqual({ + error: "Couldn't remove the workstream", + }); + consoleError.mockRestore(); + }); +}); diff --git a/src/app/api/projects/[projectId]/workstreams/[workstreamId]/route.ts b/src/app/api/projects/[projectId]/workstreams/[workstreamId]/route.ts new file mode 100644 index 00000000..d1f935bb --- /dev/null +++ b/src/app/api/projects/[projectId]/workstreams/[workstreamId]/route.ts @@ -0,0 +1,83 @@ +/** + * `DELETE /api/projects/[projectId]/workstreams/[workstreamId]` (issue #410). + * + * Deselect a workstream. Keyed on `workstream.id` rather than the + * `project_workstream.id` so the card grid can call it with the id it already + * renders, and so a repeat call is a clean 404 rather than a dangling handle. + * + * The cascade rules (`../cascade`) decide the outcome: + * - work orders exist → 409, `blocked: true`, never overridable + * - configuration exists → 409, `requiresConfirmation: true`, until + * the caller repeats the request with + * `?confirm=true` + * - otherwise → deleted + * + * The 409 bodies keep the `{ error: string }` shape and add the flags and + * counts the UI needs to raise the right dialog. + */ +import { NextRequest, NextResponse } from "next/server"; +import { authorizeWorkstreamRequest } from "../authorize"; +import { decideDeselect } from "../cascade"; +import { deselectWorkstream, findSelection } from "../queries"; + +type Params = { params: Promise<{ projectId: string; workstreamId: string }> }; + +export async function DELETE(req: NextRequest, props: Params) { + const { projectId, workstreamId } = await props.params; + const auth = await authorizeWorkstreamRequest(projectId, "manage"); + if (!auth.ok) { + return NextResponse.json({ error: auth.error }, { status: auth.status }); + } + + if (!/^\d+$/.test(workstreamId)) { + return NextResponse.json({ error: "Invalid workstream" }, { status: 400 }); + } + + const selection = await findSelection(auth.projectId, BigInt(workstreamId)); + if (!selection) { + return NextResponse.json( + { error: "Workstream is not selected on this project" }, + { status: 404 }, + ); + } + + const confirmed = req.nextUrl.searchParams.get("confirm") === "true"; + const decision = decideDeselect(selection.dependents, confirmed); + + if (decision.kind === "blocked") { + return NextResponse.json( + { + error: decision.reason, + blocked: true, + dependents: selection.dependents, + }, + { status: 409 }, + ); + } + + if (decision.kind === "needs-confirmation") { + return NextResponse.json( + { + error: decision.reason, + requiresConfirmation: true, + dependents: selection.dependents, + }, + { status: 409 }, + ); + } + + try { + await deselectWorkstream(selection.id); + } catch (err) { + console.error( + "DELETE /api/projects/[projectId]/workstreams/[workstreamId] failed:", + err, + ); + return NextResponse.json( + { error: "Couldn't remove the workstream" }, + { status: 500 }, + ); + } + + return NextResponse.json({ workstreamId, selected: false }); +} diff --git a/src/app/api/projects/[projectId]/workstreams/[workstreamId]/stages/[stageId]/route.test.ts b/src/app/api/projects/[projectId]/workstreams/[workstreamId]/stages/[stageId]/route.test.ts new file mode 100644 index 00000000..65320637 --- /dev/null +++ b/src/app/api/projects/[projectId]/workstreams/[workstreamId]/stages/[stageId]/route.test.ts @@ -0,0 +1,247 @@ +/** + * PATCH (rename) / DELETE `.../workstreams/[workstreamId]/stages/[stageId]` + * (issue #411). + * + * Database mocked at the module boundary (`../queries` and the authz + * repository); no connection is opened. The blocked-delete path — the one the + * acceptance criteria call out — is exercised here end to end through the + * handler, with the rules themselves covered in `../ladder.test.ts`. + */ +import { describe, expect, it, beforeEach, vi } from "vitest"; +import { NextRequest } from "next/server"; + +const { + mockGetServerSession, + mockLoadAuthzUser, + mockLoadProjectAuthzFacts, + mockFindLadder, + mockRenameStage, + mockDeleteStage, +} = vi.hoisted(() => ({ + mockGetServerSession: vi.fn(), + mockLoadAuthzUser: vi.fn(), + mockLoadProjectAuthzFacts: vi.fn(), + mockFindLadder: vi.fn(), + mockRenameStage: vi.fn(), + mockDeleteStage: vi.fn(), +})); + +vi.mock("next-auth", () => ({ getServerSession: mockGetServerSession })); +vi.mock("@/app/api/auth/[...nextauth]/authOptions", () => ({ AuthOptions: {} })); +vi.mock("@/app/repositories/projects/authzRepository", () => ({ + loadAuthzUser: mockLoadAuthzUser, + loadProjectAuthzFacts: mockLoadProjectAuthzFacts, +})); +vi.mock("../queries", () => ({ + findLadder: mockFindLadder, + renameStage: mockRenameStage, + deleteStage: mockDeleteStage, +})); + +import { DELETE, PATCH } from "./route"; + +const CLIENT_ORG = "11111111-1111-1111-1111-111111111111"; +const CONTRACTOR_ORG = "22222222-2222-2222-2222-222222222222"; + +const NO_DEPENDENTS = { + workOrders: 0, + evidenceRequirements: 0, + isCurrentStage: false, +}; + +const LADDER = { + projectWorkstreamId: "9", + workstreamId: "1", + workstreamName: "Windows", + isDefault: false, + stages: [ + { id: "100", name: "Ordered", order: 0, dependents: NO_DEPENDENTS }, + { + id: "101", + name: "Closed", + order: 1, + dependents: { ...NO_DEPENDENTS, workOrders: 4 }, + }, + ], +}; + +function signedInAs(organisationIds: string[]) { + mockGetServerSession.mockResolvedValue({ user: { dbId: "7" } }); + mockLoadAuthzUser.mockResolvedValue({ + id: 7n, + email: "someone@landlord.example", + organisationIds, + }); +} + +function projectExists() { + mockLoadProjectAuthzFacts.mockResolvedValue({ + id: 5n, + organisationId: CLIENT_ORG, + domnaAdminAccess: false, + contractorOrganisationIds: [CONTRACTOR_ORG], + }); +} + +const params = (stageId = "100") => ({ + params: Promise.resolve({ + projectId: "5", + // The catalogue `workstream.id`; the mocked ladder maps it to + // `project_workstream.id` 9, which is what the writes are asserted on. + workstreamId: "1", + stageId, + }), +}); + +const url = (stageId = "100") => + `http://localhost/api/projects/5/workstreams/1/stages/${stageId}`; + +function patchRequest(body: unknown, stageId = "100") { + return new NextRequest(url(stageId), { + method: "PATCH", + body: JSON.stringify(body), + headers: { "content-type": "application/json" }, + }); +} + +beforeEach(() => { + vi.clearAllMocks(); + mockFindLadder.mockResolvedValue(LADDER); + mockRenameStage.mockResolvedValue({ kind: "renamed" }); + mockDeleteStage.mockResolvedValue({ kind: "deleted" }); +}); + +describe("PATCH", () => { + beforeEach(() => { + signedInAs([CLIENT_ORG]); + projectExists(); + }); + + it("401s without a session", async () => { + mockGetServerSession.mockResolvedValue(null); + const res = await PATCH(patchRequest({ name: "On site" }), params()); + expect(res.status).toBe(401); + }); + + it("403s a caller who may view but not manage", async () => { + signedInAs([CONTRACTOR_ORG]); + const res = await PATCH(patchRequest({ name: "On site" }), params()); + expect(res.status).toBe(403); + expect(mockRenameStage).not.toHaveBeenCalled(); + }); + + it("renames a stage", async () => { + const res = await PATCH(patchRequest({ name: "On site" }), params()); + expect(res.status).toBe(200); + expect(await res.json()).toEqual({ stageId: "100", renamed: true }); + expect(mockRenameStage).toHaveBeenCalledWith(9n, 100n, "On site"); + }); + + it("400s a patch with no name", async () => { + const res = await PATCH(patchRequest({}), params()); + expect(res.status).toBe(400); + expect(mockRenameStage).not.toHaveBeenCalled(); + }); + + it("ignores any attempt to set status, order or the dates", async () => { + // None of those columns is this issue's to write (ADR-0021): unknown keys + // are dropped by the schema, so they never reach the rename. + const res = await PATCH( + patchRequest({ + name: "On site", + status: "complete", + order: 0, + startDate: "2026-09-03", + }), + params(), + ); + expect(res.status).toBe(200); + expect(mockRenameStage).toHaveBeenCalledWith(9n, 100n, "On site"); + }); + + it("404s a stage that is not in this workstream's ladder", async () => { + const res = await PATCH(patchRequest({ name: "On site" }, "999"), params("999")); + expect(res.status).toBe(404); + expect(mockRenameStage).not.toHaveBeenCalled(); + }); + + it("404s a workstream of another project", async () => { + mockFindLadder.mockResolvedValue(null); + const res = await PATCH(patchRequest({ name: "On site" }), params()); + expect(res.status).toBe(404); + expect(mockRenameStage).not.toHaveBeenCalled(); + }); + + it("passes a rejected name back as a 400 with its reason", async () => { + mockRenameStage.mockResolvedValue({ + kind: "rejected", + reason: 'This workstream already has a "Closed" stage.', + }); + const res = await PATCH(patchRequest({ name: "Closed" }), params()); + expect(res.status).toBe(400); + expect((await res.json()).error).toContain("already has"); + }); +}); + +describe("DELETE", () => { + beforeEach(() => { + signedInAs([CLIENT_ORG]); + projectExists(); + }); + + it("403s a caller who may view but not manage", async () => { + signedInAs([CONTRACTOR_ORG]); + const res = await DELETE(new NextRequest(url()), params()); + expect(res.status).toBe(403); + expect(mockDeleteStage).not.toHaveBeenCalled(); + }); + + it("deletes a stage", async () => { + const res = await DELETE(new NextRequest(url()), params()); + expect(res.status).toBe(200); + expect(await res.json()).toEqual({ stageId: "100", deleted: true }); + expect(mockDeleteStage).toHaveBeenCalledWith(9n, 100n); + }); + + it("409s a blocked delete, flagged so the UI can tell it from a failure", async () => { + mockDeleteStage.mockResolvedValue({ + kind: "blocked", + reason: + "4 work orders are in this stage. Move them to another stage before removing it.", + }); + const res = await DELETE(new NextRequest(url("101")), params("101")); + expect(res.status).toBe(409); + expect(await res.json()).toEqual({ + error: + "4 work orders are in this stage. Move them to another stage before removing it.", + blocked: true, + }); + }); + + it("404s a stage that has already gone", async () => { + mockDeleteStage.mockResolvedValue({ kind: "not-found" }); + const res = await DELETE(new NextRequest(url()), params()); + expect(res.status).toBe(404); + }); + + it("400s a non-numeric stage id", async () => { + const res = await DELETE(new NextRequest(url("abc")), params("abc")); + expect(res.status).toBe(400); + expect(mockDeleteStage).not.toHaveBeenCalled(); + }); + + it("404s a workstream of another project without writing", async () => { + mockFindLadder.mockResolvedValue(null); + const res = await DELETE(new NextRequest(url()), params()); + expect(res.status).toBe(404); + expect(mockDeleteStage).not.toHaveBeenCalled(); + }); + + it("500s when the delete fails", async () => { + mockDeleteStage.mockRejectedValue(new Error("boom")); + vi.spyOn(console, "error").mockImplementation(() => {}); + const res = await DELETE(new NextRequest(url()), params()); + expect(res.status).toBe(500); + expect(await res.json()).toEqual({ error: "Couldn't remove the stage" }); + }); +}); diff --git a/src/app/api/projects/[projectId]/workstreams/[workstreamId]/stages/[stageId]/route.ts b/src/app/api/projects/[projectId]/workstreams/[workstreamId]/stages/[stageId]/route.ts new file mode 100644 index 00000000..033eef27 --- /dev/null +++ b/src/app/api/projects/[projectId]/workstreams/[workstreamId]/stages/[stageId]/route.ts @@ -0,0 +1,143 @@ +/** + * `.../workstreams/[workstreamId]/stages/[stageId]` (issue #411). + * + * PATCH — rename a stage. + * DELETE — remove a stage, subject to the ladder guardrails. + * + * The delete guardrails are the server's decision, always: the counts a + * browser is holding can be seconds out of date, and a Work order raised into + * a stage in the meantime must still block the delete. The client's job is to + * render the 409 it gets back, not to pre-empt it — the same division of + * labour the workstream deselect uses (#410). + * + * Unlike that deselect there is no `?confirm=true`: every refusal here is a + * hard rule, not a warning, because nothing it protects belongs to this + * screen. See `../ladder.ts`. + */ +import { NextRequest, NextResponse } from "next/server"; +import { z } from "zod"; +import { authorizeWorkstreamRequest } from "../../../authorize"; +import { deleteStage, findLadder, renameStage } from "../queries"; + +type Params = { + params: Promise<{ + projectId: string; + /** The catalogue `workstream.id` — see `../route.ts` and ADR-0021. */ + workstreamId: string; + stageId: string; + }>; +}; + +/** + * The name is the only field of a stage a user owns: `order` moves through the + * collection route's reorder, and `status` / `start_date` / `due_date` are not + * this issue's to write (ADR-0021). + */ +const patchSchema = z.object({ + name: z.string(), +}); + +function parseId(raw: string): bigint | null { + return /^\d+$/.test(raw) ? BigInt(raw) : null; +} + +/** PATCH — rename one stage. */ +export async function PATCH(req: NextRequest, props: Params) { + const { projectId, workstreamId: workstreamIdParam, stageId } = await props.params; + const auth = await authorizeWorkstreamRequest(projectId, "manage"); + if (!auth.ok) { + return NextResponse.json({ error: auth.error }, { status: auth.status }); + } + + const workstreamId = parseId(workstreamIdParam); + const id = parseId(stageId); + if (workstreamId === null || id === null) { + return NextResponse.json({ error: "Invalid stage" }, { status: 400 }); + } + + let body: z.infer; + try { + body = patchSchema.parse(await req.json()); + } catch { + return NextResponse.json({ error: "Invalid body" }, { status: 400 }); + } + + // Scopes the stage to the project in the path. + const ladder = await findLadder(auth.projectId, workstreamId); + if (!ladder) { + return NextResponse.json( + { error: "Workstream is not selected on this project" }, + { status: 404 }, + ); + } + if (!ladder.stages.some((stage) => stage.id === stageId)) { + return NextResponse.json({ error: "Stage not found" }, { status: 404 }); + } + + try { + const result = await renameStage( + BigInt(ladder.projectWorkstreamId), + id, + body.name, + ); + if (result.kind === "not-found") { + return NextResponse.json({ error: "Stage not found" }, { status: 404 }); + } + if (result.kind === "rejected") { + return NextResponse.json({ error: result.reason }, { status: 400 }); + } + return NextResponse.json({ stageId, renamed: true }); + } catch (err) { + console.error("PATCH .../stages/[stageId] failed:", err); + return NextResponse.json( + { error: "Couldn't rename the stage" }, + { status: 500 }, + ); + } +} + +/** DELETE — remove a stage if the guardrails allow it, then close the gap. */ +export async function DELETE(_req: NextRequest, props: Params) { + const { projectId, workstreamId: workstreamIdParam, stageId } = await props.params; + const auth = await authorizeWorkstreamRequest(projectId, "manage"); + if (!auth.ok) { + return NextResponse.json({ error: auth.error }, { status: auth.status }); + } + + const workstreamId = parseId(workstreamIdParam); + const id = parseId(stageId); + if (workstreamId === null || id === null) { + return NextResponse.json({ error: "Invalid stage" }, { status: 400 }); + } + + const ladder = await findLadder(auth.projectId, workstreamId); + if (!ladder) { + return NextResponse.json( + { error: "Workstream is not selected on this project" }, + { status: 404 }, + ); + } + + try { + const result = await deleteStage(BigInt(ladder.projectWorkstreamId), id); + + if (result.kind === "not-found") { + return NextResponse.json({ error: "Stage not found" }, { status: 404 }); + } + // 409, and `blocked` alongside the message, so the grid can tell a refusal + // from a transport failure without parsing the sentence. + if (result.kind === "blocked") { + return NextResponse.json( + { error: result.reason, blocked: true }, + { status: 409 }, + ); + } + return NextResponse.json({ stageId, deleted: true }); + } catch (err) { + console.error("DELETE .../stages/[stageId] failed:", err); + return NextResponse.json( + { error: "Couldn't remove the stage" }, + { status: 500 }, + ); + } +} diff --git a/src/app/api/projects/[projectId]/workstreams/[workstreamId]/stages/ladder.test.ts b/src/app/api/projects/[projectId]/workstreams/[workstreamId]/stages/ladder.test.ts new file mode 100644 index 00000000..521a1d99 --- /dev/null +++ b/src/app/api/projects/[projectId]/workstreams/[workstreamId]/stages/ladder.test.ts @@ -0,0 +1,193 @@ +/** + * The stage-ladder rules (issue #411). Pure: no database, no mocks needed. + */ +import { describe, expect, it } from "vitest"; +import { + DEFAULT_LADDER, + MIN_STAGES, + NO_STAGE_DEPENDENTS, + checkReorder, + checkStageName, + contiguousOrders, + decideDeleteStage, + isDefaultLadder, + type StageDependents, +} from "./ladder"; + +const dependents = (patch: Partial = {}): StageDependents => ({ + ...NO_STAGE_DEPENDENTS, + ...patch, +}); + +describe("DEFAULT_LADDER", () => { + it("is the v1 ladder from CONTEXT.md, in order", () => { + expect([...DEFAULT_LADDER]).toEqual([ + "Ordered", + "In progress", + "Completed", + "Charged", + "Closed", + ]); + }); +}); + +describe("decideDeleteStage", () => { + it("allows a delete from a ladder nothing points at", () => { + expect(decideDeleteStage(5, dependents())).toEqual({ kind: "allowed" }); + }); + + it("blocks a delete that would leave fewer than two stages", () => { + const decision = decideDeleteStage(MIN_STAGES, dependents()); + expect(decision.kind).toBe("blocked"); + expect(decision.kind === "blocked" && decision.reason).toContain( + "at least 2 stages", + ); + }); + + it("blocks a delete of a stage with work orders in it", () => { + const decision = decideDeleteStage(5, dependents({ workOrders: 3 })); + expect(decision).toEqual({ + kind: "blocked", + reason: + "3 work orders are in this stage. Move them to another stage before removing it.", + }); + }); + + it("says 'work order' in the singular for one", () => { + const decision = decideDeleteStage(5, dependents({ workOrders: 1 })); + expect(decision.kind === "blocked" && decision.reason).toBe( + "1 work order is in this stage. Move them to another stage before removing it.", + ); + }); + + it("blocks a delete of a stage an evidence requirement points at", () => { + const decision = decideDeleteStage( + 5, + dependents({ evidenceRequirements: 1 }), + ); + expect(decision.kind === "blocked" && decision.reason).toContain( + "1 evidence requirement expects", + ); + }); + + it("blocks a delete of the workstream's current stage", () => { + const decision = decideDeleteStage(5, dependents({ isCurrentStage: true })); + expect(decision.kind === "blocked" && decision.reason).toContain( + "current stage", + ); + }); + + it("reports the minimum-stages rule ahead of what is in the stage", () => { + // Both rules apply; the ladder's shape is the simpler thing to fix. + const decision = decideDeleteStage(2, dependents({ workOrders: 4 })); + expect(decision.kind === "blocked" && decision.reason).toContain( + "at least 2 stages", + ); + }); + + it("has no confirmation escape hatch — a block is final", () => { + // Guards the shape of the decision type: unlike the deselect cascade + // (#410) there is no `needs-confirmation` outcome to override. + expect( + decideDeleteStage(5, dependents({ workOrders: 1 })).kind, + ).toBe("blocked"); + }); +}); + +describe("isDefaultLadder", () => { + it("recognises the seeded ladder", () => { + expect(isDefaultLadder([...DEFAULT_LADDER])).toBe(true); + }); + + it("ignores case and surrounding whitespace", () => { + expect( + isDefaultLadder(["ordered", " In progress", "COMPLETED", "Charged", "Closed"]), + ).toBe(true); + }); + + it("is false once a stage is renamed", () => { + expect( + isDefaultLadder(["Ordered", "On site", "Completed", "Charged", "Closed"]), + ).toBe(false); + }); + + it("is false once the ladder is reordered", () => { + expect( + isDefaultLadder(["In progress", "Ordered", "Completed", "Charged", "Closed"]), + ).toBe(false); + }); + + it("is false when a stage is added or removed", () => { + expect(isDefaultLadder([...DEFAULT_LADDER, "Snagging"])).toBe(false); + expect(isDefaultLadder(DEFAULT_LADDER.slice(0, 4))).toBe(false); + }); + + it("is false for a workstream with no stages", () => { + expect(isDefaultLadder([])).toBe(false); + }); +}); + +describe("checkStageName", () => { + it("trims and collapses whitespace", () => { + expect(checkStageName(" On site ", [])).toEqual({ + ok: true, + name: "On site", + }); + }); + + it("rejects a blank name", () => { + expect(checkStageName(" ", []).ok).toBe(false); + }); + + it("rejects a name longer than 60 characters", () => { + expect(checkStageName("x".repeat(61), []).ok).toBe(false); + expect(checkStageName("x".repeat(60), []).ok).toBe(true); + }); + + it("rejects a duplicate, ignoring case", () => { + const check = checkStageName("ordered", ["Ordered", "Closed"]); + expect(check.ok).toBe(false); + expect(!check.ok && check.error).toContain("already has"); + }); + + it("lets a stage keep its own name on rename", () => { + // The caller passes the *other* stages' names, so this is not a clash. + expect(checkStageName("Ordered", ["Closed"]).ok).toBe(true); + }); +}); + +describe("checkReorder", () => { + it("accepts a permutation of the ladder", () => { + expect(checkReorder(["1", "2", "3"], ["3", "1", "2"])).toEqual({ + ok: true, + ids: ["3", "1", "2"], + }); + }); + + it("rejects a list that is missing a stage", () => { + expect(checkReorder(["1", "2", "3"], ["1", "2"]).ok).toBe(false); + }); + + it("rejects a list naming an unknown stage", () => { + expect(checkReorder(["1", "2", "3"], ["1", "2", "9"]).ok).toBe(false); + }); + + it("rejects a list repeating a stage", () => { + expect(checkReorder(["1", "2", "3"], ["1", "1", "2"]).ok).toBe(false); + }); + + it("explains a mismatch as a stale list, not a bad request", () => { + const check = checkReorder(["1", "2"], ["1"]); + expect(!check.ok && check.error).toContain("Reload"); + }); +}); + +describe("contiguousOrders", () => { + it("numbers from 0 with no gaps", () => { + expect(contiguousOrders(["7", "4", "9"])).toEqual([ + { id: "7", order: 0 }, + { id: "4", order: 1 }, + { id: "9", order: 2 }, + ]); + }); +}); diff --git a/src/app/api/projects/[projectId]/workstreams/[workstreamId]/stages/ladder.ts b/src/app/api/projects/[projectId]/workstreams/[workstreamId]/stages/ladder.ts new file mode 100644 index 00000000..81fa09d0 --- /dev/null +++ b/src/app/api/projects/[projectId]/workstreams/[workstreamId]/stages/ladder.ts @@ -0,0 +1,214 @@ +/** + * Stage-ladder rules for a Project Workstream (issue #411). + * + * Deliberately **pure** — no database client, no React — so the route + * handlers, the unit tests and the browser bundle share one copy of the rules, + * the way `../../cascade.ts` does for the deselect cascade. Every count these + * functions decide from is loaded in `./queries`. + * + * The ladder is the *only* lifecycle mechanism in v1 (CONTEXT.md, **Stage**): + * a Work order's position is its stage FK, and the terminal stage is simply + * the one with the highest `order`. That is why the guardrails here are strict + * — a ladder that loses a stage under a Work order, or whose `order` values + * develop a hole, is a workflow that has silently changed shape. + */ + +/** + * The ladder every Project Workstream starts with, in order — seeded once, + * then owned by the user (ADR-0021). + * + * The wireframe's "New / Active / Active / Active / Complete" is placeholder + * junk and is deliberately not what we seed; this is the v1 default named in + * CONTEXT.md and issue #411. + */ +export const DEFAULT_LADDER = [ + "Ordered", + "In progress", + "Completed", + "Charged", + "Closed", +] as const; + +/** + * A ladder with one stage is not a workflow — nothing can move. Two is the + * smallest ladder with a start and a terminal stage. + */ +export const MIN_STAGES = 2; + +/** Long enough for "Awaiting client sign-off", short enough to render. */ +export const MAX_STAGE_NAME_LENGTH = 60; + +/** What already points at one stage, and therefore what a delete would break. */ +export interface StageDependents { + /** `work_order.project_workstream_stage_id` rows sitting in this stage. */ + workOrders: number; + /** Evidence requirements (#412) narrowed to this stage. */ + evidenceRequirements: number; + /** Whether `project_workstream.current_stage_id` points here. */ + isCurrentStage: boolean; +} + +/** A stage nothing points at. */ +export const NO_STAGE_DEPENDENTS: StageDependents = { + workOrders: 0, + evidenceRequirements: 0, + isCurrentStage: false, +}; + +export type DeleteStageDecision = + | { kind: "blocked"; reason: string } + | { kind: "allowed" }; + +/** + * Whether a stage may be deleted from a ladder of `stageCount` stages. + * + * Unlike the workstream deselect, there is no `confirm` escape hatch: each of + * these is a hard rule, because none of what they protect is this screen's to + * throw away. Work orders and evidence requirements are other features' rows, + * `current_stage_id` is a column #411 never writes (ADR-0021), and a + * one-stage ladder is not a workflow. + * + * Checked shape-first (is the ladder still a ladder afterwards?) then + * contents, so the reason a user sees names the simplest thing that is wrong. + */ +export function decideDeleteStage( + stageCount: number, + dependents: StageDependents, +): DeleteStageDecision { + if (stageCount <= MIN_STAGES) { + return { + kind: "blocked", + reason: + `A workstream needs at least ${MIN_STAGES} stages. ` + + `Add another stage before removing this one.`, + }; + } + + if (dependents.workOrders > 0) { + const plural = dependents.workOrders === 1 ? "work order" : "work orders"; + return { + kind: "blocked", + reason: + `${dependents.workOrders} ${plural} ${dependents.workOrders === 1 ? "is" : "are"} in this stage. ` + + `Move them to another stage before removing it.`, + }; + } + + if (dependents.evidenceRequirements > 0) { + const n = dependents.evidenceRequirements; + return { + kind: "blocked", + reason: + `${n} evidence ${n === 1 ? "requirement expects" : "requirements expect"} a document at this stage. ` + + `Remove ${n === 1 ? "it" : "them"} first.`, + }; + } + + if (dependents.isCurrentStage) { + return { + kind: "blocked", + reason: + "This stage is the workstream's current stage, so it can't be removed.", + }; + } + + return { kind: "allowed" }; +} + +/** + * Whether a ladder is still the seeded default — same names, same order. + * + * Drives the "Default / Custom" badge on the overrides panel. Compared + * case-insensitively on trimmed names, so re-typing "ordered" over "Ordered" + * does not read as an override the user did not make. + */ +export function isDefaultLadder(names: readonly string[]): boolean { + if (names.length !== DEFAULT_LADDER.length) return false; + return names.every( + (name, i) => + name.trim().toLowerCase() === DEFAULT_LADDER[i].trim().toLowerCase(), + ); +} + +export type StageNameCheck = + | { ok: true; name: string } + | { ok: false; error: string }; + +/** + * Validate and normalise a stage name against the names already in the ladder. + * + * `otherNames` is every *other* stage's name — a rename must exclude the stage + * being renamed, or renaming "Charged" to "Charged" would collide with itself. + * Duplicates are rejected case-insensitively: two stages a user cannot tell + * apart make the ladder unreadable, and stage names are how work orders are + * talked about. + */ +export function checkStageName( + raw: string, + otherNames: readonly string[], +): StageNameCheck { + const name = raw.trim().replace(/\s+/g, " "); + + if (name.length === 0) { + return { ok: false, error: "Give the stage a name." }; + } + if (name.length > MAX_STAGE_NAME_LENGTH) { + return { + ok: false, + error: `Stage names can be at most ${MAX_STAGE_NAME_LENGTH} characters.`, + }; + } + const clash = otherNames.some( + (other) => other.trim().toLowerCase() === name.toLowerCase(), + ); + if (clash) { + return { ok: false, error: `This workstream already has a "${name}" stage.` }; + } + + return { ok: true, name }; +} + +export type ReorderCheck = + | { ok: true; ids: string[] } + | { ok: false; error: string }; + +/** + * Check that a requested order is a permutation of the ladder it claims to + * reorder — same ids, each exactly once. + * + * A reorder that dropped or invented an id would renumber a partial ladder and + * leave a hole in `order`, so the request is refused rather than repaired. The + * caller compares against ids re-read inside the same transaction, which is + * also what makes this the stale-client check: a ladder edited in another tab + * no longer matches, so the reorder is rejected instead of applied to a shape + * the user was not looking at. + */ +export function checkReorder( + currentIds: readonly string[], + requestedIds: readonly string[], +): ReorderCheck { + const stale = { + ok: false as const, + error: "The stage list has changed. Reload and try again.", + }; + + if (requestedIds.length !== currentIds.length) return stale; + if (new Set(requestedIds).size !== requestedIds.length) return stale; + + const current = new Set(currentIds); + if (!requestedIds.every((id) => current.has(id))) return stale; + + return { ok: true, ids: [...requestedIds] }; +} + +/** + * The `order` each id should carry: contiguous from 0, in the given sequence. + * + * Every write path that changes the shape of a ladder — add, delete, reorder — + * ends here, so `order` is contiguous by construction rather than by repair. + */ +export function contiguousOrders( + ids: readonly string[], +): Array<{ id: string; order: number }> { + return ids.map((id, order) => ({ id, order })); +} diff --git a/src/app/api/projects/[projectId]/workstreams/[workstreamId]/stages/queries.ts b/src/app/api/projects/[projectId]/workstreams/[workstreamId]/stages/queries.ts new file mode 100644 index 00000000..6d9dc893 --- /dev/null +++ b/src/app/api/projects/[projectId]/workstreams/[workstreamId]/stages/queries.ts @@ -0,0 +1,517 @@ +/** + * Persistence for the stage-configuration setup screen (issue #411). + * + * The route handlers and the server-rendered page both read through here, so + * the two always agree on shape — the page paints first, the handlers serve + * every refetch after it. Same split as `../../queries.ts` for #410. + * + * Several columns are never written from this module, by decision (ADR-0021): + * - `project_workstream.current_stage_id` — deferred to #426; v1 derives a + * workstream's position from its Work orders' stage FKs. + * - `work_order.status` — the stage FK is the only progress mechanism. + * - `project_workstream_stage.start_date` / `due_date` — dates describe a + * work order's delivery, not a rung of a workflow, so a ladder stage has + * no date to hold. The columns stay nullable and stay NULL; whether they + * survive is a schema question for later. + * + * `project_workstream_stage.status` is the awkward case: it is + * `NOT NULL` with no database default, so a row cannot be inserted without a + * value. Inserts therefore write the placeholder constant below, once, and no + * update path ever touches the column again. See ADR-0021. + */ +import { db } from "@/app/db/db"; +import { and, eq, inArray, sql } from "drizzle-orm"; +import { + projectWorkstream, + projectWorkstreamEvidenceRequirement, + projectWorkstreamStage, + workOrder, + workstream, +} from "@/app/db/schema/projects/projects"; +import { + DEFAULT_LADDER, + checkReorder, + checkStageName, + contiguousOrders, + decideDeleteStage, + isDefaultLadder, + type StageDependents, +} from "./ladder"; + +/** + * The value written into the `NOT NULL` `status` column on insert. + * + * Not a lifecycle state and not read by anything — the stage's meaning is its + * position in the ladder. Matches what `seed-projects-dashboard.ts` already + * writes, so existing rows and new ones agree. When #426 gives the column a + * real value set, that issue owns the backfill. + */ +export const PLACEHOLDER_STAGE_STATUS = "active"; + +/** One stage as the API and the page render it. */ +export interface LadderStage { + /** `project_workstream_stage.id`, serialised — bigints do not survive JSON. */ + id: string; + name: string; + /** Contiguous from 0 within its ladder. */ + order: number; + /** What points at this stage — drives the delete guardrails' explanations. */ + dependents: StageDependents; +} + +/** One Project Workstream's whole ladder. */ +export interface WorkstreamLadder { + /** `project_workstream.id` — the id the CRUD routes are keyed on. */ + projectWorkstreamId: string; + /** `workstream.id`, the reference-data row. */ + workstreamId: string; + workstreamName: string; + stages: LadderStage[]; + /** True while the ladder is still the seeded default, names and order. */ + isDefault: boolean; +} + +/** One row of the stage read, before it is serialised for the wire. */ +type StageRow = { + id: bigint; + projectWorkstreamId: bigint; + name: string; + order: number; + workOrders: number; + evidenceRequirements: number; + isCurrentStage: boolean; +}; + +/** + * Every stage of the Project Workstreams matching `where`, with the counts the + * delete guardrails need. + * + * One round trip: the two child tables are left-joined and counted with + * `count(distinct)`, so the join fan-out between them does not inflate either + * number. `current_stage_id` is read (never written) to spot the stage a + * workstream points at. + */ +async function loadStageRows( + where: ReturnType, +): Promise { + return db + .select({ + id: projectWorkstreamStage.id, + projectWorkstreamId: projectWorkstreamStage.projectWorkstreamId, + name: projectWorkstreamStage.name, + order: projectWorkstreamStage.order, + workOrders: sql`count(distinct ${workOrder.id})::int`, + evidenceRequirements: sql`count(distinct ${projectWorkstreamEvidenceRequirement.id})::int`, + isCurrentStage: sql`coalesce(bool_or(${projectWorkstream.currentStageId} = ${projectWorkstreamStage.id}), false)`, + }) + .from(projectWorkstreamStage) + .innerJoin( + projectWorkstream, + eq(projectWorkstream.id, projectWorkstreamStage.projectWorkstreamId), + ) + .leftJoin( + workOrder, + eq(workOrder.projectWorkstreamStageId, projectWorkstreamStage.id), + ) + .leftJoin( + projectWorkstreamEvidenceRequirement, + eq( + projectWorkstreamEvidenceRequirement.projectWorkstreamStageId, + projectWorkstreamStage.id, + ), + ) + .where(where) + .groupBy(projectWorkstreamStage.id) + .orderBy(projectWorkstreamStage.order, projectWorkstreamStage.id); +} + +function toLadderStage(row: StageRow): LadderStage { + return { + id: row.id.toString(), + name: row.name, + order: row.order, + dependents: { + workOrders: row.workOrders, + evidenceRequirements: row.evidenceRequirements, + isCurrentStage: row.isCurrentStage, + }, + }; +} + +function toLadder( + workstreamRow: { + projectWorkstreamId: bigint; + workstreamId: bigint; + workstreamName: string; + }, + rows: StageRow[], +): WorkstreamLadder { + const stages = rows.map(toLadderStage); + return { + projectWorkstreamId: workstreamRow.projectWorkstreamId.toString(), + workstreamId: workstreamRow.workstreamId.toString(), + workstreamName: workstreamRow.workstreamName, + stages, + isDefault: isDefaultLadder(stages.map((s) => s.name)), + }; +} + +/** + * The Project Workstreams a project has selected, catalogue name included. + * + * `workstreamId` narrows to one, and is the **catalogue** `workstream.id` — + * see `findLadder` for why the routes are keyed on that rather than on + * `project_workstream.id`. + */ +async function loadSelectedWorkstreams( + projectId: bigint, + workstreamId?: bigint, +) { + return db + .select({ + projectWorkstreamId: projectWorkstream.id, + workstreamId: projectWorkstream.workstreamId, + workstreamName: workstream.name, + }) + .from(projectWorkstream) + .innerJoin(workstream, eq(workstream.id, projectWorkstream.workstreamId)) + .where( + workstreamId === undefined + ? eq(projectWorkstream.projectId, projectId) + : and( + eq(projectWorkstream.projectId, projectId), + eq(projectWorkstream.workstreamId, workstreamId), + ), + ) + .orderBy(projectWorkstream.id); +} + +/** + * Every selected workstream's ladder for one project — what the setup screen + * renders on first paint. + * + * A workstream with no stages comes back with an empty `stages` array rather + * than being omitted: that is precisely the state the import readiness gate + * (#414) reports as incomplete, so the screen must show it. + */ +export async function listProjectLadders( + projectId: bigint, +): Promise { + const workstreams = await loadSelectedWorkstreams(projectId); + if (workstreams.length === 0) return []; + + const rows = await loadStageRows(eq(projectWorkstream.projectId, projectId)); + + const byWorkstream = new Map(); + for (const row of rows) { + const key = row.projectWorkstreamId.toString(); + const bucket = byWorkstream.get(key); + if (bucket) bucket.push(row); + else byWorkstream.set(key, [row]); + } + + return workstreams.map((w) => + toLadder(w, byWorkstream.get(w.projectWorkstreamId.toString()) ?? []), + ); +} + +/** + * One workstream's ladder on one project, or null when that project has not + * selected it. + * + * **Keyed on `workstream.id`**, the catalogue row — not on + * `project_workstream.id`. The stages routes are nested under the same + * `/workstreams/[workstreamId]` segment as the deselect endpoint (#410), and a + * URL segment must mean one thing: `/workstreams/9` and `/workstreams/9/stages` + * name the same workstream. See ADR-0021. + * + * The null is load-bearing: it is how every route handler here checks that the + * workstream in the path is selected on the project in the path, so an id from + * another project reads as 404 rather than being edited. The returned + * `projectWorkstreamId` is what the write functions below take, so the + * translation happens exactly once per request, at the edge. + */ +export async function findLadder( + projectId: bigint, + workstreamId: bigint, +): Promise { + const [workstreamRow] = await loadSelectedWorkstreams(projectId, workstreamId); + if (!workstreamRow) return null; + + const rows = await loadStageRows( + eq( + projectWorkstreamStage.projectWorkstreamId, + workstreamRow.projectWorkstreamId, + ), + ); + return toLadder(workstreamRow, rows); +} + +/** + * Seed the default ladder for every workstream of `projectId` that has none. + * + * Idempotent, and idempotent under concurrency: the workstream rows are locked + * `FOR UPDATE` before their stage counts are read, so two simultaneous visits + * to the setup screen cannot both find "no stages" and both insert. The second + * transaction blocks, re-reads, and finds the ladder already there. That lock + * is what makes "seeded exactly once per workstream" true rather than likely. + * + * Returns the ids seeded, so the caller can tell a first visit from a revisit. + */ +export async function seedDefaultLadders( + projectId: bigint, +): Promise { + return db.transaction(async (tx) => { + const workstreams = await tx + .select({ id: projectWorkstream.id }) + .from(projectWorkstream) + .where(eq(projectWorkstream.projectId, projectId)) + .for("update"); + + if (workstreams.length === 0) return []; + + const withStages = await tx + .select({ id: projectWorkstreamStage.projectWorkstreamId }) + .from(projectWorkstreamStage) + .where( + inArray( + projectWorkstreamStage.projectWorkstreamId, + workstreams.map((w) => w.id), + ), + ) + .groupBy(projectWorkstreamStage.projectWorkstreamId); + + const seeded = new Set(withStages.map((row) => row.id.toString())); + const empty = workstreams.filter((w) => !seeded.has(w.id.toString())); + if (empty.length === 0) return []; + + await tx.insert(projectWorkstreamStage).values( + empty.flatMap((w) => + DEFAULT_LADDER.map((name, order) => ({ + projectWorkstreamId: w.id, + name, + order, + status: PLACEHOLDER_STAGE_STATUS, + })), + ), + ); + + return empty.map((w) => w.id.toString()); + }); +} + +/** The stages of one workstream, locked for the rest of the transaction. */ +async function lockedStages( + tx: Parameters[0]>[0], + projectWorkstreamId: bigint, +) { + return tx + .select({ + id: projectWorkstreamStage.id, + name: projectWorkstreamStage.name, + order: projectWorkstreamStage.order, + }) + .from(projectWorkstreamStage) + .where(eq(projectWorkstreamStage.projectWorkstreamId, projectWorkstreamId)) + .orderBy(projectWorkstreamStage.order, projectWorkstreamStage.id) + .for("update"); +} + +/** Rewrite `order` so the given sequence is contiguous from 0. */ +async function writeOrders( + tx: Parameters[0]>[0], + ids: string[], +): Promise { + for (const { id, order } of contiguousOrders(ids)) { + await tx + .update(projectWorkstreamStage) + .set({ order }) + .where(eq(projectWorkstreamStage.id, BigInt(id))); + } +} + +export type AddStageResult = + | { kind: "added"; stageId: string } + | { kind: "rejected"; reason: string }; + +/** + * Append a stage to the end of a ladder. + * + * New stages land last because that is the only position that cannot change + * what the existing ladder means — inserting in the middle would silently + * renumber stages that Work orders already sit in. Reordering afterwards is + * one click away, and is an explicit act. + * + * The name is re-checked against names re-read inside the transaction, so two + * tabs adding "Snagging" at once cannot both succeed. + */ +export async function addStage( + projectWorkstreamId: bigint, + stage: { name: string }, +): Promise { + return db.transaction(async (tx) => { + const existing = await lockedStages(tx, projectWorkstreamId); + + const check = checkStageName( + stage.name, + existing.map((s) => s.name), + ); + if (!check.ok) return { kind: "rejected", reason: check.error }; + + const [inserted] = await tx + .insert(projectWorkstreamStage) + .values({ + projectWorkstreamId, + name: check.name, + order: existing.length, + status: PLACEHOLDER_STAGE_STATUS, + }) + .returning({ id: projectWorkstreamStage.id }); + + // The append is only contiguous if the ladder already was; a ladder that + // arrived here with a hole is straightened rather than extended crooked. + await writeOrders(tx, [ + ...existing.map((s) => s.id.toString()), + inserted.id.toString(), + ]); + + return { kind: "added", stageId: inserted.id.toString() }; + }); +} + +export type RenameStageResult = + | { kind: "renamed" } + | { kind: "not-found" } + | { kind: "rejected"; reason: string }; + +/** + * Rename a stage. + * + * The name is the only field of a stage a user owns: `order` changes go + * through `reorderStages`, and `status`, `status_description`, `start_date` + * and `due_date` are not this issue's to write (ADR-0021). The uniqueness + * check runs against names re-read under the lock, excluding this stage — so a + * stage may always keep its own name. + */ +export async function renameStage( + projectWorkstreamId: bigint, + stageId: bigint, + name: string, +): Promise { + return db.transaction(async (tx) => { + const existing = await lockedStages(tx, projectWorkstreamId); + if (!existing.some((s) => s.id === stageId)) return { kind: "not-found" }; + + const check = checkStageName( + name, + existing.filter((s) => s.id !== stageId).map((s) => s.name), + ); + if (!check.ok) return { kind: "rejected", reason: check.error }; + + await tx + .update(projectWorkstreamStage) + .set({ name: check.name }) + .where(eq(projectWorkstreamStage.id, stageId)); + + return { kind: "renamed" }; + }); +} + +export type DeleteStageResult = + | { kind: "deleted" } + | { kind: "not-found" } + | { kind: "blocked"; reason: string }; + +/** + * Delete a stage, then close the gap its `order` left behind. + * + * The guardrails are evaluated against counts re-read **inside** the + * transaction with the ladder locked, not against whatever the client last + * saw: a Work order raised into this stage a second ago must block the delete, + * and the browser cannot know that. `decideDeleteStage` makes the decision; + * this function only gathers the facts and applies the outcome. + */ +export async function deleteStage( + projectWorkstreamId: bigint, + stageId: bigint, +): Promise { + return db.transaction(async (tx) => { + const existing = await lockedStages(tx, projectWorkstreamId); + if (!existing.some((s) => s.id === stageId)) return { kind: "not-found" }; + + const [counts] = await tx + .select({ + workOrders: sql`count(distinct ${workOrder.id})::int`, + evidenceRequirements: sql`count(distinct ${projectWorkstreamEvidenceRequirement.id})::int`, + isCurrentStage: sql`coalesce(bool_or(${projectWorkstream.currentStageId} = ${projectWorkstreamStage.id}), false)`, + }) + .from(projectWorkstreamStage) + .innerJoin( + projectWorkstream, + eq(projectWorkstream.id, projectWorkstreamStage.projectWorkstreamId), + ) + .leftJoin( + workOrder, + eq(workOrder.projectWorkstreamStageId, projectWorkstreamStage.id), + ) + .leftJoin( + projectWorkstreamEvidenceRequirement, + eq( + projectWorkstreamEvidenceRequirement.projectWorkstreamStageId, + projectWorkstreamStage.id, + ), + ) + .where(eq(projectWorkstreamStage.id, stageId)) + .groupBy(projectWorkstreamStage.id); + + const decision = decideDeleteStage(existing.length, { + workOrders: counts?.workOrders ?? 0, + evidenceRequirements: counts?.evidenceRequirements ?? 0, + isCurrentStage: counts?.isCurrentStage ?? false, + }); + if (decision.kind === "blocked") { + return { kind: "blocked", reason: decision.reason }; + } + + await tx + .delete(projectWorkstreamStage) + .where(eq(projectWorkstreamStage.id, stageId)); + + await writeOrders( + tx, + existing.filter((s) => s.id !== stageId).map((s) => s.id.toString()), + ); + + return { kind: "deleted" }; + }); +} + +export type ReorderStagesResult = + | { kind: "reordered" } + | { kind: "rejected"; reason: string }; + +/** + * Rewrite a ladder's `order` to the sequence the client asked for. + * + * The request must name every stage of the ladder exactly once; a request that + * does not is refused as stale rather than applied to a shape the user was not + * looking at. The comparison is against ids re-read under the lock, which is + * what makes the staleness check meaningful. + */ +export async function reorderStages( + projectWorkstreamId: bigint, + requestedIds: string[], +): Promise { + return db.transaction(async (tx) => { + const existing = await lockedStages(tx, projectWorkstreamId); + + const check = checkReorder( + existing.map((s) => s.id.toString()), + requestedIds, + ); + if (!check.ok) return { kind: "rejected", reason: check.error }; + + await writeOrders(tx, check.ids); + return { kind: "reordered" }; + }); +} diff --git a/src/app/api/projects/[projectId]/workstreams/[workstreamId]/stages/route.test.ts b/src/app/api/projects/[projectId]/workstreams/[workstreamId]/stages/route.test.ts new file mode 100644 index 00000000..6c495f44 --- /dev/null +++ b/src/app/api/projects/[projectId]/workstreams/[workstreamId]/stages/route.test.ts @@ -0,0 +1,277 @@ +/** + * GET / POST / PATCH `.../workstreams/[workstreamId]/stages` (issue #411). + * + * The id in the path is the catalogue `workstream.id`; `findLadder` translates + * it to the `project_workstream.id` the writes take (ADR-0021), so the mocked + * ladder below is what decides which workstream is written to. + * + * The database is mocked at the module boundary (`./queries` and the authz + * repository); no connection is opened. The authorization *decisions* are the + * real ones from `@/lib/projects/authz` — only the facts they read are faked. + */ +import { describe, expect, it, beforeEach, vi } from "vitest"; +import { NextRequest } from "next/server"; + +const { + mockGetServerSession, + mockLoadAuthzUser, + mockLoadProjectAuthzFacts, + mockFindLadder, + mockAddStage, + mockReorderStages, +} = vi.hoisted(() => ({ + mockGetServerSession: vi.fn(), + mockLoadAuthzUser: vi.fn(), + mockLoadProjectAuthzFacts: vi.fn(), + mockFindLadder: vi.fn(), + mockAddStage: vi.fn(), + mockReorderStages: vi.fn(), +})); + +vi.mock("next-auth", () => ({ getServerSession: mockGetServerSession })); +vi.mock("@/app/api/auth/[...nextauth]/authOptions", () => ({ AuthOptions: {} })); +vi.mock("@/app/repositories/projects/authzRepository", () => ({ + loadAuthzUser: mockLoadAuthzUser, + loadProjectAuthzFacts: mockLoadProjectAuthzFacts, +})); +vi.mock("./queries", () => ({ + findLadder: mockFindLadder, + addStage: mockAddStage, + reorderStages: mockReorderStages, +})); + +import { GET, PATCH, POST } from "./route"; + +const CLIENT_ORG = "11111111-1111-1111-1111-111111111111"; +const CONTRACTOR_ORG = "22222222-2222-2222-2222-222222222222"; +const OTHER_ORG = "33333333-3333-3333-3333-333333333333"; + +const NO_DEPENDENTS = { + workOrders: 0, + evidenceRequirements: 0, + isCurrentStage: false, +}; + +const LADDER = { + projectWorkstreamId: "9", + workstreamId: "1", + workstreamName: "Windows", + isDefault: true, + stages: [ + { id: "100", name: "Ordered", order: 0, dependents: NO_DEPENDENTS }, + { id: "101", name: "Closed", order: 1, dependents: NO_DEPENDENTS }, + ], +}; + +function signedInAs(organisationIds: string[]) { + mockGetServerSession.mockResolvedValue({ user: { dbId: "7" } }); + mockLoadAuthzUser.mockResolvedValue({ + id: 7n, + email: "someone@landlord.example", + organisationIds, + }); +} + +function projectExists() { + mockLoadProjectAuthzFacts.mockResolvedValue({ + id: 5n, + organisationId: CLIENT_ORG, + domnaAdminAccess: false, + contractorOrganisationIds: [CONTRACTOR_ORG], + }); +} + +const params = (projectId = "5", workstreamId = "1") => ({ + params: Promise.resolve({ projectId, workstreamId }), +}); + +const url = (projectId = "5", workstreamId = "1") => + `http://localhost/api/projects/${projectId}/workstreams/${workstreamId}/stages`; + +function jsonRequest(method: string, body: unknown) { + return new NextRequest(url(), { + method, + body: JSON.stringify(body), + headers: { "content-type": "application/json" }, + }); +} + +beforeEach(() => { + vi.clearAllMocks(); + mockFindLadder.mockResolvedValue(LADDER); + mockAddStage.mockResolvedValue({ kind: "added", stageId: "102" }); + mockReorderStages.mockResolvedValue({ kind: "reordered" }); +}); + +describe("GET", () => { + it("401s without a session", async () => { + mockGetServerSession.mockResolvedValue(null); + const res = await GET(new NextRequest(url()), params()); + expect(res.status).toBe(401); + expect(await res.json()).toEqual({ error: "Unauthorised" }); + }); + + it("404s a project the caller may not see, rather than 403", async () => { + signedInAs([OTHER_ORG]); + projectExists(); + const res = await GET(new NextRequest(url()), params()); + expect(res.status).toBe(404); + expect(mockFindLadder).not.toHaveBeenCalled(); + }); + + it("400s a non-numeric workstream id", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + const res = await GET(new NextRequest(url("5", "abc")), params("5", "abc")); + expect(res.status).toBe(400); + }); + + it("404s a workstream that is not selected on this project", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + mockFindLadder.mockResolvedValue(null); + const res = await GET(new NextRequest(url()), params()); + expect(res.status).toBe(404); + }); + + it("returns the ladder and whether the caller may edit it", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + const res = await GET(new NextRequest(url()), params()); + expect(res.status).toBe(200); + expect(await res.json()).toEqual({ ladder: LADDER, canManage: true }); + expect(mockFindLadder).toHaveBeenCalledWith(5n, 1n); + }); + + it("lets a contractor read the ladder but not manage it", async () => { + signedInAs([CONTRACTOR_ORG]); + projectExists(); + const res = await GET(new NextRequest(url()), params()); + expect(res.status).toBe(200); + expect((await res.json()).canManage).toBe(false); + }); +}); + +describe("POST", () => { + beforeEach(() => { + signedInAs([CLIENT_ORG]); + projectExists(); + }); + + it("403s a caller who may view but not manage", async () => { + signedInAs([CONTRACTOR_ORG]); + const res = await POST(jsonRequest("POST", { name: "Snagging" }), params()); + expect(res.status).toBe(403); + expect(mockAddStage).not.toHaveBeenCalled(); + }); + + it("adds a stage", async () => { + const res = await POST(jsonRequest("POST", { name: "Snagging" }), params()); + expect(res.status).toBe(201); + expect(await res.json()).toEqual({ stageId: "102" }); + expect(mockAddStage).toHaveBeenCalledWith(9n, { name: "Snagging" }); + }); + + it("ignores dates on the way in — a stage has none (ADR-0021)", async () => { + const res = await POST( + jsonRequest("POST", { + name: "Snagging", + startDate: "2026-09-03", + dueDate: "2026-12-01", + }), + params(), + ); + expect(res.status).toBe(201); + expect(mockAddStage).toHaveBeenCalledWith(9n, { name: "Snagging" }); + }); + + it("400s a body with no name", async () => { + const res = await POST(jsonRequest("POST", {}), params()); + expect(res.status).toBe(400); + expect(await res.json()).toEqual({ error: "Invalid body" }); + }); + + it("passes a rejected name back as a 400 with its reason", async () => { + mockAddStage.mockResolvedValue({ + kind: "rejected", + reason: 'This workstream already has a "Ordered" stage.', + }); + const res = await POST(jsonRequest("POST", { name: "Ordered" }), params()); + expect(res.status).toBe(400); + expect((await res.json()).error).toContain("already has"); + }); + + it("404s a workstream of another project without writing", async () => { + mockFindLadder.mockResolvedValue(null); + const res = await POST(jsonRequest("POST", { name: "Snagging" }), params()); + expect(res.status).toBe(404); + expect(mockAddStage).not.toHaveBeenCalled(); + }); + + it("500s when the write fails", async () => { + mockAddStage.mockRejectedValue(new Error("boom")); + vi.spyOn(console, "error").mockImplementation(() => {}); + const res = await POST(jsonRequest("POST", { name: "Snagging" }), params()); + expect(res.status).toBe(500); + expect(await res.json()).toEqual({ error: "Couldn't add the stage" }); + }); +}); + +describe("PATCH (reorder)", () => { + beforeEach(() => { + signedInAs([CLIENT_ORG]); + projectExists(); + }); + + it("403s a caller who may not manage", async () => { + signedInAs([CONTRACTOR_ORG]); + const res = await PATCH( + jsonRequest("PATCH", { stageIds: ["101", "100"] }), + params(), + ); + expect(res.status).toBe(403); + expect(mockReorderStages).not.toHaveBeenCalled(); + }); + + it("reorders the ladder", async () => { + const res = await PATCH( + jsonRequest("PATCH", { stageIds: ["101", "100"] }), + params(), + ); + expect(res.status).toBe(200); + expect(await res.json()).toEqual({ reordered: true }); + expect(mockReorderStages).toHaveBeenCalledWith(9n, ["101", "100"]); + }); + + it("409s a stale list rather than applying it", async () => { + mockReorderStages.mockResolvedValue({ + kind: "rejected", + reason: "The stage list has changed. Reload and try again.", + }); + const res = await PATCH( + jsonRequest("PATCH", { stageIds: ["101"] }), + params(), + ); + expect(res.status).toBe(409); + expect((await res.json()).error).toContain("Reload"); + }); + + it("400s a body that is not a list of ids", async () => { + const res = await PATCH( + jsonRequest("PATCH", { stageIds: [100, 101] }), + params(), + ); + expect(res.status).toBe(400); + expect(mockReorderStages).not.toHaveBeenCalled(); + }); + + it("404s a workstream of another project without writing", async () => { + mockFindLadder.mockResolvedValue(null); + const res = await PATCH( + jsonRequest("PATCH", { stageIds: ["101", "100"] }), + params(), + ); + expect(res.status).toBe(404); + expect(mockReorderStages).not.toHaveBeenCalled(); + }); +}); diff --git a/src/app/api/projects/[projectId]/workstreams/[workstreamId]/stages/route.ts b/src/app/api/projects/[projectId]/workstreams/[workstreamId]/stages/route.ts new file mode 100644 index 00000000..d152439c --- /dev/null +++ b/src/app/api/projects/[projectId]/workstreams/[workstreamId]/stages/route.ts @@ -0,0 +1,175 @@ +/** + * `/api/projects/[projectId]/workstreams/[workstreamId]/stages` (issue #411). + * + * GET — one workstream's ladder, stages in `order`, with the counts that + * explain why a stage may not be deletable. + * POST — add a stage to the end of the ladder. + * PATCH — reorder the whole ladder (`{ stageIds }`, every id exactly once). + * + * Rename and delete are keyed on a single stage and live on + * `./[stageId]/route.ts`. + * + * Keyed on `workstream.id` — the catalogue row — because these routes are + * nested under the same `/workstreams/[workstreamId]` segment as the deselect + * endpoint (#410), and one segment must mean one thing. Next.js enforces the + * shared slug name; the shared *meaning* is ours to keep. `findLadder` + * translates to the `project_workstream.id` the writes take, once, and returns + * null for a workstream this project has not selected — which is how a + * cross-project id becomes a 404 rather than an edit. See ADR-0021. + * + * Authorization is `../../authorize` unchanged (#410): view to read, manage to + * write, and a project the caller cannot see reads as 404 rather than 403. + */ +import { NextRequest, NextResponse } from "next/server"; +import { z } from "zod"; +import { authorizeWorkstreamRequest } from "../../authorize"; +import { addStage, findLadder, reorderStages } from "./queries"; + +type Params = { + params: Promise<{ projectId: string; workstreamId: string }>; +}; + +/** + * A stage is a name and a position, and the position is decided by where it is + * added — so a name is the whole body. The `start_date` / `due_date` columns + * exist on the table but describe a work order's delivery rather than a rung + * of a workflow; they are deliberately left NULL (ADR-0021), so there is + * nothing here to set them with. + */ +const addSchema = z.object({ + name: z.string(), +}); + +const reorderSchema = z.object({ + /** Every stage id of this ladder, in the order they should end up in. */ + stageIds: z.array(z.string().regex(/^\d+$/, "Stage ids must be numeric")), +}); + +/** Parses `[workstreamId]`; null for anything that is not a bare id. */ +function parseWorkstreamId(raw: string): bigint | null { + return /^\d+$/.test(raw) ? BigInt(raw) : null; +} + +/** GET — the ladder, re-read from the database on every request. */ +export async function GET(_req: NextRequest, props: Params) { + const { projectId, workstreamId: workstreamIdParam } = await props.params; + const auth = await authorizeWorkstreamRequest(projectId, "view"); + if (!auth.ok) { + return NextResponse.json({ error: auth.error }, { status: auth.status }); + } + + const workstreamId = parseWorkstreamId(workstreamIdParam); + if (workstreamId === null) { + return NextResponse.json({ error: "Invalid workstream" }, { status: 400 }); + } + + const ladder = await findLadder(auth.projectId, workstreamId); + if (!ladder) { + return NextResponse.json( + { error: "Workstream is not selected on this project" }, + { status: 404 }, + ); + } + + return NextResponse.json({ ladder, canManage: auth.canManage }); +} + +/** POST — append a stage. */ +export async function POST(req: NextRequest, props: Params) { + const { projectId, workstreamId: workstreamIdParam } = await props.params; + const auth = await authorizeWorkstreamRequest(projectId, "manage"); + if (!auth.ok) { + return NextResponse.json({ error: auth.error }, { status: auth.status }); + } + + const workstreamId = parseWorkstreamId(workstreamIdParam); + if (workstreamId === null) { + return NextResponse.json({ error: "Invalid workstream" }, { status: 400 }); + } + + let body: z.infer; + try { + body = addSchema.parse(await req.json()); + } catch { + return NextResponse.json({ error: "Invalid body" }, { status: 400 }); + } + + // Existence and ownership before the write, and the translation from the + // catalogue id in the path to the `project_workstream.id` the write takes. + const ladder = await findLadder(auth.projectId, workstreamId); + if (!ladder) { + return NextResponse.json( + { error: "Workstream is not selected on this project" }, + { status: 404 }, + ); + } + + try { + const result = await addStage(BigInt(ladder.projectWorkstreamId), { + name: body.name, + }); + + if (result.kind === "rejected") { + return NextResponse.json({ error: result.reason }, { status: 400 }); + } + return NextResponse.json({ stageId: result.stageId }, { status: 201 }); + } catch (err) { + console.error("POST .../workstreams/[workstreamId]/stages failed:", err); + return NextResponse.json( + { error: "Couldn't add the stage" }, + { status: 500 }, + ); + } +} + +/** + * PATCH — reorder the ladder. + * + * The whole sequence is sent, not a "move up" instruction, so the server never + * has to guess what the client was looking at: a list that no longer matches + * the ladder is rejected as stale (409) rather than partially applied. + */ +export async function PATCH(req: NextRequest, props: Params) { + const { projectId, workstreamId: workstreamIdParam } = await props.params; + const auth = await authorizeWorkstreamRequest(projectId, "manage"); + if (!auth.ok) { + return NextResponse.json({ error: auth.error }, { status: auth.status }); + } + + const workstreamId = parseWorkstreamId(workstreamIdParam); + if (workstreamId === null) { + return NextResponse.json({ error: "Invalid workstream" }, { status: 400 }); + } + + let body: z.infer; + try { + body = reorderSchema.parse(await req.json()); + } catch { + return NextResponse.json({ error: "Invalid body" }, { status: 400 }); + } + + const ladder = await findLadder(auth.projectId, workstreamId); + if (!ladder) { + return NextResponse.json( + { error: "Workstream is not selected on this project" }, + { status: 404 }, + ); + } + + try { + const result = await reorderStages( + BigInt(ladder.projectWorkstreamId), + body.stageIds, + ); + if (result.kind === "rejected") { + return NextResponse.json({ error: result.reason }, { status: 409 }); + } + return NextResponse.json({ reordered: true }); + } catch (err) { + console.error("PATCH .../workstreams/[workstreamId]/stages failed:", err); + return NextResponse.json( + { error: "Couldn't reorder the stages" }, + { status: 500 }, + ); + } +} diff --git a/src/app/api/projects/[projectId]/workstreams/authorize.ts b/src/app/api/projects/[projectId]/workstreams/authorize.ts new file mode 100644 index 00000000..130bf18d --- /dev/null +++ b/src/app/api/projects/[projectId]/workstreams/authorize.ts @@ -0,0 +1,71 @@ +/** + * Request authorization for the workstream-selection endpoints (issue #410). + * + * Thin wiring only: the session comes from NextAuth, the facts from the + * projects authz repository, and every *decision* from `@/lib/projects/authz` + * (#408). Nothing here re-implements a permission rule. + * + * A project the caller cannot see is reported as 404, never 403, so project + * existence is not leaked outside its organisation — matching the guard in + * `src/app/projects/authz.ts`. + */ +import { getServerSession } from "next-auth"; +import { AuthOptions } from "@/app/api/auth/[...nextauth]/authOptions"; +import { + loadAuthzUser, + loadProjectAuthzFacts, +} from "@/app/repositories/projects/authzRepository"; +import { canManageProject, canViewProject } from "@/lib/projects/authz"; + +export type AuthorizeFailure = { error: string; status: 400 | 401 | 403 | 404 }; + +export type AuthorizeSuccess = { + projectId: bigint; + /** Whether the caller may edit the selection, not merely read it. */ + canManage: boolean; +}; + +export type AuthorizeResult = + | ({ ok: true } & AuthorizeSuccess) + | ({ ok: false } & AuthorizeFailure); + +/** + * Resolve the caller's standing on `projectIdParam`. + * + * `capability` is what the request needs: `"view"` for a read, `"manage"` for + * a write. The returned `canManage` lets a read tell the client whether to + * render the grid editable. + */ +export async function authorizeWorkstreamRequest( + projectIdParam: string, + capability: "view" | "manage", +): Promise { + const session = await getServerSession(AuthOptions); + if (!session?.user?.dbId) { + return { ok: false, error: "Unauthorised", status: 401 }; + } + + if (!/^\d+$/.test(projectIdParam)) { + return { ok: false, error: "Invalid project", status: 400 }; + } + const projectId = BigInt(projectIdParam); + + const [user, project] = await Promise.all([ + loadAuthzUser(BigInt(session.user.dbId)), + loadProjectAuthzFacts(projectId), + ]); + + if (!user) return { ok: false, error: "Unauthorised", status: 401 }; + if (!project) return { ok: false, error: "Project not found", status: 404 }; + + if (!canViewProject(user, project)) { + return { ok: false, error: "Project not found", status: 404 }; + } + + const canManage = canManageProject(user, project); + if (capability === "manage" && !canManage) { + return { ok: false, error: "Forbidden", status: 403 }; + } + + return { ok: true, projectId, canManage }; +} diff --git a/src/app/api/projects/[projectId]/workstreams/cascade.test.ts b/src/app/api/projects/[projectId]/workstreams/cascade.test.ts new file mode 100644 index 00000000..1ff58f54 --- /dev/null +++ b/src/app/api/projects/[projectId]/workstreams/cascade.test.ts @@ -0,0 +1,124 @@ +/** + * The deselect cascade rules (issue #410). Pure logic — no mocks needed. + */ +import { describe, expect, it } from "vitest"; +import { + NO_DEPENDENTS, + cascadingCount, + decideDeselect, + describeDependents, + type WorkstreamDependents, +} from "./cascade"; + +function dependents( + overrides: Partial = {}, +): WorkstreamDependents { + return { ...NO_DEPENDENTS, ...overrides }; +} + +describe("decideDeselect", () => { + it("allows deselecting a workstream nothing hangs off", () => { + expect(decideDeselect(dependents(), false)).toEqual({ kind: "allowed" }); + }); + + it("asks for confirmation when stages are configured", () => { + const decision = decideDeselect(dependents({ stages: 5 }), false); + expect(decision.kind).toBe("needs-confirmation"); + expect(decision).toHaveProperty("reason", expect.stringContaining("5 stages")); + }); + + it("asks for confirmation when evidence requirements exist", () => { + expect( + decideDeselect(dependents({ evidenceRequirements: 1 }), false).kind, + ).toBe("needs-confirmation"); + }); + + it("asks for confirmation when a contractor is assigned", () => { + expect(decideDeselect(dependents({ contractors: 1 }), false).kind).toBe( + "needs-confirmation", + ); + }); + + it("proceeds once the user has confirmed", () => { + expect( + decideDeselect( + dependents({ stages: 5, evidenceRequirements: 2, contractors: 1 }), + true, + ), + ).toEqual({ kind: "allowed" }); + }); + + it("blocks when work orders exist", () => { + const decision = decideDeselect(dependents({ workOrders: 3 }), false); + expect(decision.kind).toBe("blocked"); + expect(decision).toHaveProperty( + "reason", + expect.stringContaining("3 work orders"), + ); + }); + + it("keeps blocking work orders even when the user confirms", () => { + // Confirmation acknowledges a warning; it is not an override. + expect(decideDeselect(dependents({ workOrders: 1 }), true).kind).toBe( + "blocked", + ); + }); + + it("reports the work-order block ahead of the configuration warning", () => { + const decision = decideDeselect( + dependents({ stages: 4, workOrders: 2 }), + false, + ); + expect(decision.kind).toBe("blocked"); + }); + + it("singularises a lone work order", () => { + expect(decideDeselect(dependents({ workOrders: 1 }), false)).toHaveProperty( + "reason", + expect.stringContaining("1 work order "), + ); + }); +}); + +describe("describeDependents", () => { + it("is empty when nothing is configured", () => { + expect(describeDependents(dependents())).toBe(""); + }); + + it("singularises a single dependent", () => { + expect(describeDependents(dependents({ stages: 1 }))).toBe("1 stage"); + }); + + it("joins the last pair with 'and'", () => { + expect( + describeDependents( + dependents({ stages: 5, evidenceRequirements: 2, contractors: 1 }), + ), + ).toBe("5 stages, 2 evidence requirements and 1 contractor assignment"); + }); + + it("omits the categories that are empty", () => { + expect(describeDependents(dependents({ stages: 3, contractors: 2 }))).toBe( + "3 stages and 2 contractor assignments", + ); + }); + + it("ignores work orders, which are never deleted by a cascade", () => { + expect(describeDependents(dependents({ workOrders: 9 }))).toBe(""); + }); +}); + +describe("cascadingCount", () => { + it("counts only the rows a confirmed deselect would delete", () => { + expect( + cascadingCount( + dependents({ + stages: 5, + evidenceRequirements: 2, + contractors: 1, + workOrders: 7, + }), + ), + ).toBe(8); + }); +}); diff --git a/src/app/api/projects/[projectId]/workstreams/cascade.ts b/src/app/api/projects/[projectId]/workstreams/cascade.ts new file mode 100644 index 00000000..583e0902 --- /dev/null +++ b/src/app/api/projects/[projectId]/workstreams/cascade.ts @@ -0,0 +1,105 @@ +/** + * Deselect cascade rules for a Project Workstream (issue #410). + * + * Deliberately **pure** — it imports no database client and no React — so the + * route handler, the unit tests and the browser bundle can all share one copy + * of the rules. The counts themselves are loaded in `./queries`. + * + * Two rules, in priority order: + * 1. **Work orders block.** Work has been issued against the workstream; the + * selection can no longer be withdrawn from the setup screen. + * 2. **Configuration warns.** Stages, evidence requirements and contractor + * assignments are the workstream's own configuration — deselecting throws + * them away, so the user must confirm first. + * + * Everything else deselects silently. + */ + +/** What already hangs off one Project Workstream. */ +export interface WorkstreamDependents { + stages: number; + evidenceRequirements: number; + contractors: number; + workOrders: number; +} + +/** An unselected workstream, or a selected one nothing hangs off yet. */ +export const NO_DEPENDENTS: WorkstreamDependents = { + stages: 0, + evidenceRequirements: 0, + contractors: 0, + workOrders: 0, +}; + +export type DeselectDecision = + | { kind: "blocked"; reason: string } + | { kind: "needs-confirmation"; reason: string } + | { kind: "allowed" }; + +/** The dependents that are destroyed by a confirmed deselect. */ +const CASCADING: Array<{ + key: keyof WorkstreamDependents; + one: string; + many: string; +}> = [ + { key: "stages", one: "stage", many: "stages" }, + { + key: "evidenceRequirements", + one: "evidence requirement", + many: "evidence requirements", + }, + { + key: "contractors", + one: "contractor assignment", + many: "contractor assignments", + }, +]; + +/** How many rows a confirmed deselect would delete. */ +export function cascadingCount(dependents: WorkstreamDependents): number { + return CASCADING.reduce((total, { key }) => total + dependents[key], 0); +} + +/** `"5 stages, 1 evidence requirement and 2 contractor assignments"`. */ +export function describeDependents(dependents: WorkstreamDependents): string { + const parts = CASCADING.filter(({ key }) => dependents[key] > 0).map( + ({ key, one, many }) => + `${dependents[key]} ${dependents[key] === 1 ? one : many}`, + ); + if (parts.length === 0) return ""; + if (parts.length === 1) return parts[0]; + return `${parts.slice(0, -1).join(", ")} and ${parts[parts.length - 1]}`; +} + +/** + * Whether a deselect may proceed. + * + * `confirmed` is the user having acknowledged the warning (the `?confirm=true` + * query parameter on DELETE). It never unblocks a work-order block — that is a + * hard rule, not a warning. + */ +export function decideDeselect( + dependents: WorkstreamDependents, + confirmed: boolean, +): DeselectDecision { + if (dependents.workOrders > 0) { + const plural = dependents.workOrders === 1 ? "work order" : "work orders"; + return { + kind: "blocked", + reason: + `This workstream has ${dependents.workOrders} ${plural} against it. ` + + `Work orders must be removed before the workstream can be taken off the project.`, + }; + } + + if (!confirmed && cascadingCount(dependents) > 0) { + return { + kind: "needs-confirmation", + reason: + `Removing this workstream also deletes ${describeDependents(dependents)}. ` + + `This can't be undone.`, + }; + } + + return { kind: "allowed" }; +} diff --git a/src/app/api/projects/[projectId]/workstreams/queries.ts b/src/app/api/projects/[projectId]/workstreams/queries.ts new file mode 100644 index 00000000..4032ba2d --- /dev/null +++ b/src/app/api/projects/[projectId]/workstreams/queries.ts @@ -0,0 +1,248 @@ +/** + * Persistence for the workstream-selection setup screen (issue #410). + * + * The route handlers and the server-rendered page both read through here, so + * the two always agree on shape — the page renders the first paint and the + * handlers serve every refetch afterwards. + * + * The workstream catalogue is reference data seeded by #407 (migration 0274); + * it is always read from the `workstream` table, never hard-coded. + */ +import { db } from "@/app/db/db"; +import { and, eq, or, sql } from "drizzle-orm"; +import { + projectWorkstream, + projectWorkstreamContractor, + projectWorkstreamEvidenceRequirement, + projectWorkstreamStage, + workOrder, + workstream, +} from "@/app/db/schema/projects/projects"; +import { NO_DEPENDENTS, type WorkstreamDependents } from "./cascade"; + +/** One card in the grid: a catalogue row plus this project's standing on it. */ +export interface WorkstreamOption { + /** `workstream.id`, serialised — the id the POST/DELETE endpoints take. */ + id: string; + name: string; + description: string; + selected: boolean; + /** `project_workstream.id` when selected, else null. */ + projectWorkstreamId: string | null; + /** All zero when unselected. Drives the badges and the deselect warnings. */ + dependents: WorkstreamDependents; +} + +interface DependentRow extends WorkstreamDependents { + id: bigint; + workstreamId: bigint; +} + +/** + * Count what hangs off each Project Workstream matching `where`. + * + * One round trip: the four child tables are left-joined and counted with + * `count(distinct)`, so the join fan-out between them does not inflate the + * numbers. A Work order reaches its Project Workstream by two independent FKs + * (its stage and its contractor assignment) — both are followed, so a row + * hanging off either path still blocks the deselect. + */ +async function loadDependentRows( + where: ReturnType, +): Promise { + return db + .select({ + id: projectWorkstream.id, + workstreamId: projectWorkstream.workstreamId, + stages: sql`count(distinct ${projectWorkstreamStage.id})::int`, + evidenceRequirements: sql`count(distinct ${projectWorkstreamEvidenceRequirement.id})::int`, + contractors: sql`count(distinct ${projectWorkstreamContractor.id})::int`, + workOrders: sql`count(distinct ${workOrder.id})::int`, + }) + .from(projectWorkstream) + .leftJoin( + projectWorkstreamStage, + eq(projectWorkstreamStage.projectWorkstreamId, projectWorkstream.id), + ) + .leftJoin( + projectWorkstreamEvidenceRequirement, + eq( + projectWorkstreamEvidenceRequirement.projectWorkstreamId, + projectWorkstream.id, + ), + ) + .leftJoin( + projectWorkstreamContractor, + eq(projectWorkstreamContractor.projectWorkstreamId, projectWorkstream.id), + ) + .leftJoin( + workOrder, + or( + eq(workOrder.projectWorkstreamStageId, projectWorkstreamStage.id), + eq( + workOrder.projectWorkstreamContractorId, + projectWorkstreamContractor.id, + ), + ), + ) + .where(where) + .groupBy(projectWorkstream.id, projectWorkstream.workstreamId); +} + +/** + * The whole card grid for one project: every seeded workstream, marked with + * whether this project has selected it and what is configured underneath. + */ +export async function listWorkstreamOptions( + projectId: bigint, +): Promise { + const [catalogue, selections] = await Promise.all([ + db + .select({ + id: workstream.id, + name: workstream.name, + description: workstream.description, + }) + .from(workstream) + .orderBy(workstream.id), + loadDependentRows(eq(projectWorkstream.projectId, projectId)), + ]); + + const byWorkstreamId = new Map( + selections.map((row) => [row.workstreamId.toString(), row]), + ); + + return catalogue.map((row) => { + const selection = byWorkstreamId.get(row.id.toString()); + return { + id: row.id.toString(), + name: row.name, + description: row.description, + selected: Boolean(selection), + projectWorkstreamId: selection ? selection.id.toString() : null, + dependents: selection + ? { + stages: selection.stages, + evidenceRequirements: selection.evidenceRequirements, + contractors: selection.contractors, + workOrders: selection.workOrders, + } + : { ...NO_DEPENDENTS }, + }; + }); +} + +/** True when `workstreamId` is a real catalogue row. */ +export async function workstreamExists(workstreamId: bigint): Promise { + const [found] = await db + .select({ id: workstream.id }) + .from(workstream) + .where(eq(workstream.id, workstreamId)) + .limit(1); + return Boolean(found); +} + +/** + * The `project_workstream` row for one (project, workstream) pair, with its + * dependent counts. Null when the workstream is not selected on the project. + */ +export async function findSelection( + projectId: bigint, + workstreamId: bigint, +): Promise<{ id: bigint; dependents: WorkstreamDependents } | null> { + const [row] = await loadDependentRows( + and( + eq(projectWorkstream.projectId, projectId), + eq(projectWorkstream.workstreamId, workstreamId), + ), + ); + if (!row) return null; + return { + id: row.id, + dependents: { + stages: row.stages, + evidenceRequirements: row.evidenceRequirements, + contractors: row.contractors, + workOrders: row.workOrders, + }, + }; +} + +/** + * Select a workstream for a project, returning the `project_workstream` id. + * + * Idempotent: re-selecting an already-selected workstream returns the existing + * row rather than a duplicate. `project_workstream` carries no unique index on + * (project_id, workstream_id), so the check-then-insert is done inside a + * transaction — the narrowest guard available without a migration. + */ +export async function selectWorkstream( + projectId: bigint, + workstreamId: bigint, +): Promise<{ id: bigint; created: boolean }> { + return db.transaction(async (tx) => { + const [existing] = await tx + .select({ id: projectWorkstream.id }) + .from(projectWorkstream) + .where( + and( + eq(projectWorkstream.projectId, projectId), + eq(projectWorkstream.workstreamId, workstreamId), + ), + ) + .limit(1); + + if (existing) return { id: existing.id, created: false }; + + const [inserted] = await tx + .insert(projectWorkstream) + .values({ projectId, workstreamId }) + .returning({ id: projectWorkstream.id }); + + return { id: inserted.id, created: true }; + }); +} + +/** + * Deselect a workstream, deleting the configuration that hangs off it. + * + * Callers must have run `decideDeselect` first: this deletes stages, evidence + * requirements and contractor assignments unconditionally, and would fail on + * the work-order FK if any work had been issued. + * + * `current_stage_id` is nulled before the stages go, because the Project + * Workstream points back at one of its own stages. + */ +export async function deselectWorkstream( + projectWorkstreamId: bigint, +): Promise { + await db.transaction(async (tx) => { + await tx + .update(projectWorkstream) + .set({ currentStageId: null }) + .where(eq(projectWorkstream.id, projectWorkstreamId)); + + await tx + .delete(projectWorkstreamEvidenceRequirement) + .where( + eq( + projectWorkstreamEvidenceRequirement.projectWorkstreamId, + projectWorkstreamId, + ), + ); + + await tx + .delete(projectWorkstreamContractor) + .where( + eq(projectWorkstreamContractor.projectWorkstreamId, projectWorkstreamId), + ); + + await tx + .delete(projectWorkstreamStage) + .where(eq(projectWorkstreamStage.projectWorkstreamId, projectWorkstreamId)); + + await tx + .delete(projectWorkstream) + .where(eq(projectWorkstream.id, projectWorkstreamId)); + }); +} diff --git a/src/app/api/projects/[projectId]/workstreams/route.test.ts b/src/app/api/projects/[projectId]/workstreams/route.test.ts new file mode 100644 index 00000000..1fd78f5c --- /dev/null +++ b/src/app/api/projects/[projectId]/workstreams/route.test.ts @@ -0,0 +1,228 @@ +/** + * GET / POST `/api/projects/[projectId]/workstreams` (issue #410). + * + * The database is mocked at the module boundary (`./queries` and the authz + * repository); no connection is opened. The authorization *decisions* are the + * real ones from `@/lib/projects/authz` — only the facts they read are faked. + */ +import { describe, expect, it, beforeEach, vi } from "vitest"; +import { NextRequest } from "next/server"; + +const { + mockGetServerSession, + mockLoadAuthzUser, + mockLoadProjectAuthzFacts, + mockListWorkstreamOptions, + mockSelectWorkstream, + mockWorkstreamExists, +} = vi.hoisted(() => ({ + mockGetServerSession: vi.fn(), + mockLoadAuthzUser: vi.fn(), + mockLoadProjectAuthzFacts: vi.fn(), + mockListWorkstreamOptions: vi.fn(), + mockSelectWorkstream: vi.fn(), + mockWorkstreamExists: vi.fn(), +})); + +vi.mock("next-auth", () => ({ getServerSession: mockGetServerSession })); +vi.mock("@/app/api/auth/[...nextauth]/authOptions", () => ({ AuthOptions: {} })); +vi.mock("@/app/repositories/projects/authzRepository", () => ({ + loadAuthzUser: mockLoadAuthzUser, + loadProjectAuthzFacts: mockLoadProjectAuthzFacts, +})); +vi.mock("./queries", () => ({ + listWorkstreamOptions: mockListWorkstreamOptions, + selectWorkstream: mockSelectWorkstream, + workstreamExists: mockWorkstreamExists, +})); + +import { GET, POST } from "./route"; + +const CLIENT_ORG = "11111111-1111-1111-1111-111111111111"; +const CONTRACTOR_ORG = "22222222-2222-2222-2222-222222222222"; +const OTHER_ORG = "33333333-3333-3333-3333-333333333333"; + +const CATALOGUE = [ + { + id: "1", + name: "Windows", + description: "Replacement and repair of windows.", + selected: true, + projectWorkstreamId: "9", + dependents: { + stages: 5, + evidenceRequirements: 0, + contractors: 0, + workOrders: 0, + }, + }, + { + id: "2", + name: "Doors", + description: "Replacement and repair of doors.", + selected: false, + projectWorkstreamId: null, + dependents: { + stages: 0, + evidenceRequirements: 0, + contractors: 0, + workOrders: 0, + }, + }, +]; + +function signedInAs(organisationIds: string[]) { + mockGetServerSession.mockResolvedValue({ user: { dbId: "7" } }); + mockLoadAuthzUser.mockResolvedValue({ + id: 7n, + email: "someone@landlord.example", + organisationIds, + }); +} + +function projectExists() { + mockLoadProjectAuthzFacts.mockResolvedValue({ + id: 5n, + organisationId: CLIENT_ORG, + domnaAdminAccess: false, + contractorOrganisationIds: [CONTRACTOR_ORG], + }); +} + +const params = (projectId = "5") => ({ params: Promise.resolve({ projectId }) }); + +function getRequest(projectId = "5") { + return new NextRequest( + `http://localhost/api/projects/${projectId}/workstreams`, + ); +} + +function postRequest(body: unknown, projectId = "5") { + return new NextRequest( + `http://localhost/api/projects/${projectId}/workstreams`, + { + method: "POST", + body: JSON.stringify(body), + headers: { "content-type": "application/json" }, + }, + ); +} + +beforeEach(() => { + vi.clearAllMocks(); + mockListWorkstreamOptions.mockResolvedValue(CATALOGUE); + mockWorkstreamExists.mockResolvedValue(true); + mockSelectWorkstream.mockResolvedValue({ id: 42n, created: true }); +}); + +describe("GET", () => { + it("401s without a session", async () => { + mockGetServerSession.mockResolvedValue(null); + const res = await GET(getRequest(), params()); + expect(res.status).toBe(401); + expect(await res.json()).toEqual({ error: "Unauthorised" }); + }); + + it("400s on a non-numeric project id", async () => { + signedInAs([CLIENT_ORG]); + const res = await GET(getRequest("abc"), params("abc")); + expect(res.status).toBe(400); + expect(await res.json()).toEqual({ error: "Invalid project" }); + }); + + it("404s when the project does not exist", async () => { + signedInAs([CLIENT_ORG]); + mockLoadProjectAuthzFacts.mockResolvedValue(null); + const res = await GET(getRequest(), params()); + expect(res.status).toBe(404); + }); + + it("404s rather than 403s for a user outside the project", async () => { + signedInAs([OTHER_ORG]); + projectExists(); + const res = await GET(getRequest(), params()); + expect(res.status).toBe(404); + expect(mockListWorkstreamOptions).not.toHaveBeenCalled(); + }); + + it("returns the catalogue with the project's selections", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + const res = await GET(getRequest(), params()); + expect(res.status).toBe(200); + expect(await res.json()).toEqual({ + workstreams: CATALOGUE, + canManage: true, + }); + expect(mockListWorkstreamOptions).toHaveBeenCalledWith(5n); + }); + + it("lets a contractor read but marks the grid unmanageable", async () => { + signedInAs([CONTRACTOR_ORG]); + projectExists(); + const res = await GET(getRequest(), params()); + expect(res.status).toBe(200); + expect(await res.json()).toMatchObject({ canManage: false }); + }); +}); + +describe("POST", () => { + it("403s for a contractor, who may see setup but not edit it", async () => { + signedInAs([CONTRACTOR_ORG]); + projectExists(); + const res = await POST(postRequest({ workstreamId: "2" }), params()); + expect(res.status).toBe(403); + expect(await res.json()).toEqual({ error: "Forbidden" }); + expect(mockSelectWorkstream).not.toHaveBeenCalled(); + }); + + it("400s on a body without a numeric workstreamId", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + const res = await POST(postRequest({ workstreamId: "windows" }), params()); + expect(res.status).toBe(400); + expect(await res.json()).toEqual({ error: "Invalid body" }); + }); + + it("404s when the workstream is not in the catalogue", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + mockWorkstreamExists.mockResolvedValue(false); + const res = await POST(postRequest({ workstreamId: "99" }), params()); + expect(res.status).toBe(404); + expect(mockSelectWorkstream).not.toHaveBeenCalled(); + }); + + it("201s on a new selection", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + const res = await POST(postRequest({ workstreamId: "2" }), params()); + expect(res.status).toBe(201); + expect(await res.json()).toEqual({ + projectWorkstreamId: "42", + workstreamId: "2", + selected: true, + }); + expect(mockSelectWorkstream).toHaveBeenCalledWith(5n, 2n); + }); + + it("200s when the workstream was already selected", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + mockSelectWorkstream.mockResolvedValue({ id: 9n, created: false }); + const res = await POST(postRequest({ workstreamId: "1" }), params()); + expect(res.status).toBe(200); + expect(await res.json()).toMatchObject({ projectWorkstreamId: "9" }); + }); + + it("500s without leaking the driver error", async () => { + signedInAs([CLIENT_ORG]); + projectExists(); + const consoleError = vi.spyOn(console, "error").mockImplementation(() => {}); + mockSelectWorkstream.mockRejectedValue(new Error("connection reset")); + const res = await POST(postRequest({ workstreamId: "2" }), params()); + expect(res.status).toBe(500); + expect(await res.json()).toEqual({ error: "Couldn't add the workstream" }); + consoleError.mockRestore(); + }); +}); diff --git a/src/app/api/projects/[projectId]/workstreams/route.ts b/src/app/api/projects/[projectId]/workstreams/route.ts new file mode 100644 index 00000000..3a03e1a6 --- /dev/null +++ b/src/app/api/projects/[projectId]/workstreams/route.ts @@ -0,0 +1,72 @@ +/** + * `/api/projects/[projectId]/workstreams` (issue #410). + * + * GET — the seeded workstream catalogue, marked with this project's + * selection and what is configured under each selected one. + * POST — select a workstream (insert a `project_workstream` row). + * + * Deselect lives on `[workstreamId]/route.ts` because its cascade rules need + * to name a single workstream. + */ +import { NextRequest, NextResponse } from "next/server"; +import { z } from "zod"; +import { authorizeWorkstreamRequest } from "./authorize"; +import { listWorkstreamOptions, selectWorkstream, workstreamExists } from "./queries"; + +type Params = { params: Promise<{ projectId: string }> }; + +const selectSchema = z.object({ + /** `workstream.id` as a string — ids are bigint and do not survive JSON. */ + workstreamId: z.string().regex(/^\d+$/, "workstreamId must be a numeric id"), +}); + +/** GET — the card grid's data, re-read from the DB on every request. */ +export async function GET(_req: NextRequest, props: Params) { + const { projectId } = await props.params; + const auth = await authorizeWorkstreamRequest(projectId, "view"); + if (!auth.ok) { + return NextResponse.json({ error: auth.error }, { status: auth.status }); + } + + const workstreams = await listWorkstreamOptions(auth.projectId); + return NextResponse.json({ workstreams, canManage: auth.canManage }); +} + +/** POST — select a workstream for the project. Idempotent. */ +export async function POST(req: NextRequest, props: Params) { + const { projectId } = await props.params; + const auth = await authorizeWorkstreamRequest(projectId, "manage"); + if (!auth.ok) { + return NextResponse.json({ error: auth.error }, { status: auth.status }); + } + + let body: z.infer; + try { + body = selectSchema.parse(await req.json()); + } catch { + return NextResponse.json({ error: "Invalid body" }, { status: 400 }); + } + const workstreamId = BigInt(body.workstreamId); + + if (!(await workstreamExists(workstreamId))) { + return NextResponse.json({ error: "Workstream not found" }, { status: 404 }); + } + + try { + const { id, created } = await selectWorkstream(auth.projectId, workstreamId); + return NextResponse.json( + { + projectWorkstreamId: id.toString(), + workstreamId: body.workstreamId, + selected: true, + }, + { status: created ? 201 : 200 }, + ); + } catch (err) { + console.error("POST /api/projects/[projectId]/workstreams failed:", err); + return NextResponse.json( + { error: "Couldn't add the workstream" }, + { status: 500 }, + ); + } +} diff --git a/src/app/api/projects/route.ts b/src/app/api/projects/route.ts new file mode 100644 index 00000000..8e0c3bd1 --- /dev/null +++ b/src/app/api/projects/route.ts @@ -0,0 +1,80 @@ +import { NextRequest, NextResponse } from "next/server"; +import { getServerSession } from "next-auth"; +import { AuthOptions } from "@/app/api/auth/[...nextauth]/authOptions"; +import { canManageProject } from "@/lib/projects/authz"; +import { + createProjectSchema, + prospectiveProjectFacts, +} from "@/lib/projects/createProject"; +import { loadAuthzUserByEmail } from "@/app/repositories/projects/authzRepository"; +import { + insertProject, + organisationExists, + projectTypeExists, +} from "@/app/repositories/projects/projectsRepository"; + +/** + * POST /api/projects — create an Ara Project (issue #409). + * + * The authorization question "may this user create a project for this + * organisation?" is answered by the *existing* guard: build the facts the + * project would have once created and ask `canManageProject`. That keeps + * creation on the same rule as every other management action instead of + * inventing a parallel one. + * + * The rule has a consequence worth naming: `domna_admin_access` gates the + * `internal` role, so a Domna user creating a project for an organisation they + * are not a member of must grant that access. Without it they would be + * creating a project they could not then see, and the guard refuses rather + * than producing an orphan. + */ +export async function POST(req: NextRequest) { + const session = await getServerSession(AuthOptions); + if (!session?.user?.email) { + return NextResponse.json({ error: "Unauthorised" }, { status: 401 }); + } + + const user = await loadAuthzUserByEmail(session.user.email); + if (!user) { + return NextResponse.json({ error: "Unauthorised" }, { status: 401 }); + } + + const parsed = createProjectSchema.safeParse(await req.json().catch(() => null)); + if (!parsed.success) { + return NextResponse.json( + { error: parsed.error.issues[0]?.message ?? "Invalid body" }, + { status: 400 }, + ); + } + const draft = parsed.data; + + if (!canManageProject(user, prospectiveProjectFacts(draft))) { + return NextResponse.json( + { + error: + "You cannot create a project for that organisation. Granting Domna admin access is required for an organisation you are not a member of.", + }, + { status: 403 }, + ); + } + + // Checked after authorization so an unauthorized caller cannot use the + // difference between 400 and 403 to probe which organisations exist. + const projectTypeId = BigInt(draft.projectTypeId); + const [orgOk, typeOk] = await Promise.all([ + organisationExists(draft.organisationId), + projectTypeExists(projectTypeId), + ]); + if (!orgOk) { + return NextResponse.json({ error: "Unknown organisation" }, { status: 400 }); + } + if (!typeOk) { + return NextResponse.json({ error: "Unknown project type" }, { status: 400 }); + } + + const id = await insertProject({ ...draft, projectTypeId }); + + // `id` is a bigint; JSON cannot carry one, so the client gets a string and + // uses it to build the next wizard step's path. + return NextResponse.json({ id: id.toString() }, { status: 201 }); +} diff --git a/src/app/components/DateInput.tsx b/src/app/components/DateInput.tsx new file mode 100644 index 00000000..20530110 --- /dev/null +++ b/src/app/components/DateInput.tsx @@ -0,0 +1,166 @@ +"use client"; + +import * as React from "react"; +import { CalendarDaysIcon } from "@heroicons/react/24/outline"; +import { cn } from "@/lib/utils"; +import { Calendar } from "@/app/shadcn_components/ui/calendar"; +import { Input } from "@/app/shadcn_components/ui/input"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/app/shadcn_components/ui/popover"; +import { + formatUkDate, + formatUkDateWhileTyping, + isoToLocalDate, + localDateToIso, + parseUkDate, +} from "@/utils/dates"; + +export interface DateInputProps + extends Omit< + React.InputHTMLAttributes, + "value" | "onChange" | "type" + > { + /** + * The date as `YYYY-MM-DD`. Empty, `null` and `undefined` all mean "no date" + * — an optional field's form value is `undefined` before it is touched. + */ + value: string | null | undefined; + /** + * Called with `YYYY-MM-DD` once a real date has been typed, and `""` while + * the field is still incomplete. A *complete* entry that is not a real date + * (`31/02/2026`) is passed through as typed, so the caller's schema rejects + * it — see the note in the component body. + */ + onChange: (value: string) => void; + /** Cypress hook. The calendar trigger derives its own from this, suffixed. */ + "data-testid"?: string; +} + +/** + * A date field that reads and writes `dd/mm/yyyy`. + * + * Use this rather than `` anywhere a user enters a date. + * The native control's display format follows the *browser's* locale, not the + * document's — so a US-configured browser shows `mm/dd/yyyy` on a UK product, + * with no attribute available to override it. + * + * A date can be typed or picked. The calendar in the popover replaces the one + * lost with the native control, and writes through the same value, so neither + * route is privileged: picking fills the text, typing moves the grid. + * + * The value crossing this boundary is always `YYYY-MM-DD`, so form state, + * request bodies and `date` columns are unaffected — only what the user sees + * changes. + */ +export const DateInput = React.forwardRef( + function DateInput({ value, onChange, ...props }, ref) { + // Normalised first: an untouched optional field is `undefined` and a + // cleared one is `""`. Treating them as different values would reset the + // text mid-keystroke, because typing reports `""` for incomplete input. + const current = value ?? ""; + + const [pickerOpen, setPickerOpen] = React.useState(false); + + // The displayed text and the value it produced, held together so the pair + // can never disagree. Half-typed text ("03/0") has no ISO form, so the + // field cannot be driven by `value` alone. + const [state, setState] = React.useState(() => ({ + text: formatUkDate(current), + value: current, + })); + + // Adjusting state during render, not in an effect: when the form resets or + // sets this field from outside, the incoming value is authoritative and + // the displayed text is rebuilt from it. React re-runs the render with the + // new state before touching the DOM, so this costs no extra paint. + if (current !== state.value) { + setState({ text: formatUkDate(current), value: current }); + } + + function handleChange(event: React.ChangeEvent) { + const raw = event.target.value; + const text = formatUkDateWhileTyping(raw, { + deleting: raw.length < state.text.length, + }); + + // Three outcomes, and the middle one is the reason this is not just + // `parseUkDate(text) ?? ""`. A field holding "31/02/2026" that reported + // itself empty would pass an optional-date schema silently, and the user + // would be told nothing about a date they can see in the box. So a + // finished-but-impossible date is handed over as typed, where the + // schema's `YYYY-MM-DD` check rejects it. Unfinished input is genuinely + // "no date yet" and reports empty, so no error appears mid-keystroke. + const finished = text.replace(/\D/g, "").length === 8; + const next = parseUkDate(text) ?? (finished ? text : ""); + + setState({ text, value: next }); + onChange(next); + } + + function handleSelect(date: Date | undefined) { + const next = date ? localDateToIso(date) : ""; + setState({ text: formatUkDate(next), value: next }); + onChange(next); + setPickerOpen(false); + } + + // The date the grid should highlight and open on. A half-typed or + // impossible entry has none, in which case the picker opens on the current + // month rather than refusing to open. + const selected = isoToLocalDate(state.value) ?? undefined; + + return ( +
+ + + + + + + + + +
+ ); + } +); diff --git a/src/app/db/migrations/0276_romantic_synch.sql b/src/app/db/migrations/0276_romantic_synch.sql new file mode 100644 index 00000000..7ab653e6 --- /dev/null +++ b/src/app/db/migrations/0276_romantic_synch.sql @@ -0,0 +1,52 @@ +CREATE TABLE "epc_roof_window" ( + "id" bigserial PRIMARY KEY NOT NULL, + "epc_property_id" bigint NOT NULL, + "roof_window_index" integer NOT NULL, + "area_m2" double precision NOT NULL, + "u_value_raw" double precision NOT NULL, + "orientation" integer NOT NULL, + "pitch_deg" double precision NOT NULL, + "g_perpendicular" double precision NOT NULL, + "frame_factor" double precision NOT NULL, + "glazing_type" integer NOT NULL, + "window_location" jsonb NOT NULL +); +--> statement-breakpoint +CREATE TABLE "epc_room_in_roof" ( + "id" bigserial PRIMARY KEY NOT NULL, + "epc_building_part_id" bigint NOT NULL, + "floor_area" double precision NOT NULL, + "construction_age_band" text NOT NULL, + "common_wall_length_m" double precision, + "common_wall_height_m" double precision, + "gable_1_length_m" double precision, + "gable_1_height_m" double precision, + "gable_2_length_m" double precision, + "gable_2_height_m" double precision, + CONSTRAINT "epc_room_in_roof_epc_building_part_id_unique" UNIQUE("epc_building_part_id") +); +--> statement-breakpoint +CREATE TABLE "epc_room_in_roof_surface" ( + "id" bigserial PRIMARY KEY NOT NULL, + "epc_room_in_roof_id" bigint NOT NULL, + "surface_index" integer NOT NULL, + "kind" text NOT NULL, + "area_m2" double precision NOT NULL, + "insulation_thickness_mm" integer, + "insulation_type" text, + "u_value" double precision +); +--> statement-breakpoint +ALTER TABLE "epc_building_part" ADD COLUMN "wall_u_value" double precision;--> statement-breakpoint +ALTER TABLE "epc_building_part" ADD COLUMN "alt_wall_1_u_value" double precision;--> statement-breakpoint +ALTER TABLE "epc_building_part" ADD COLUMN "alt_wall_1_thickness_mm" integer;--> statement-breakpoint +ALTER TABLE "epc_building_part" ADD COLUMN "alt_wall_1_is_basement" boolean;--> statement-breakpoint +ALTER TABLE "epc_building_part" ADD COLUMN "alt_wall_2_u_value" double precision;--> statement-breakpoint +ALTER TABLE "epc_building_part" ADD COLUMN "alt_wall_2_thickness_mm" integer;--> statement-breakpoint +ALTER TABLE "epc_building_part" ADD COLUMN "alt_wall_2_is_basement" boolean;--> statement-breakpoint +ALTER TABLE "epc_property" ADD COLUMN "heating_cylinder_heat_loss" double precision;--> statement-breakpoint +ALTER TABLE "epc_roof_window" ADD CONSTRAINT "epc_roof_window_epc_property_id_epc_property_id_fk" FOREIGN KEY ("epc_property_id") REFERENCES "public"."epc_property"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "epc_room_in_roof" ADD CONSTRAINT "epc_room_in_roof_epc_building_part_id_epc_building_part_id_fk" FOREIGN KEY ("epc_building_part_id") REFERENCES "public"."epc_building_part"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "epc_room_in_roof_surface" ADD CONSTRAINT "epc_room_in_roof_surface_epc_room_in_roof_id_epc_room_in_roof_id_fk" FOREIGN KEY ("epc_room_in_roof_id") REFERENCES "public"."epc_room_in_roof"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +CREATE UNIQUE INDEX "uq_epc_roof_window_property_index" ON "epc_roof_window" USING btree ("epc_property_id","roof_window_index");--> statement-breakpoint +CREATE UNIQUE INDEX "uq_epc_room_in_roof_surface_index" ON "epc_room_in_roof_surface" USING btree ("epc_room_in_roof_id","surface_index"); \ No newline at end of file diff --git a/src/app/db/migrations/0277_woozy_prism.sql b/src/app/db/migrations/0277_woozy_prism.sql new file mode 100644 index 00000000..212f4b24 --- /dev/null +++ b/src/app/db/migrations/0277_woozy_prism.sql @@ -0,0 +1,2 @@ +ALTER TABLE "epc_building_part" DROP COLUMN "room_in_roof_floor_area";--> statement-breakpoint +ALTER TABLE "epc_building_part" DROP COLUMN "room_in_roof_construction_age_band"; \ No newline at end of file diff --git a/src/app/db/migrations/0278_living_baron_strucker.sql b/src/app/db/migrations/0278_living_baron_strucker.sql new file mode 100644 index 00000000..c42ef256 --- /dev/null +++ b/src/app/db/migrations/0278_living_baron_strucker.sql @@ -0,0 +1,17 @@ +ALTER TYPE "public"."roof_type" ADD VALUE 'Pitched, sloping ceiling, as built' BEFORE 'Roof room(s), insulated';--> statement-breakpoint +ALTER TYPE "public"."roof_type" ADD VALUE 'Pitched, sloping ceiling, 12 mm insulation' BEFORE 'Roof room(s), insulated';--> statement-breakpoint +ALTER TYPE "public"."roof_type" ADD VALUE 'Pitched, sloping ceiling, 25 mm insulation' BEFORE 'Roof room(s), insulated';--> statement-breakpoint +ALTER TYPE "public"."roof_type" ADD VALUE 'Pitched, sloping ceiling, 50 mm insulation' BEFORE 'Roof room(s), insulated';--> statement-breakpoint +ALTER TYPE "public"."roof_type" ADD VALUE 'Pitched, sloping ceiling, 75 mm insulation' BEFORE 'Roof room(s), insulated';--> statement-breakpoint +ALTER TYPE "public"."roof_type" ADD VALUE 'Pitched, sloping ceiling, 100 mm insulation' BEFORE 'Roof room(s), insulated';--> statement-breakpoint +ALTER TYPE "public"."roof_type" ADD VALUE 'Pitched, sloping ceiling, 125 mm insulation' BEFORE 'Roof room(s), insulated';--> statement-breakpoint +ALTER TYPE "public"."roof_type" ADD VALUE 'Pitched, sloping ceiling, 150 mm insulation' BEFORE 'Roof room(s), insulated';--> statement-breakpoint +ALTER TYPE "public"."roof_type" ADD VALUE 'Pitched, sloping ceiling, 175 mm insulation' BEFORE 'Roof room(s), insulated';--> statement-breakpoint +ALTER TYPE "public"."roof_type" ADD VALUE 'Pitched, sloping ceiling, 200 mm insulation' BEFORE 'Roof room(s), insulated';--> statement-breakpoint +ALTER TYPE "public"."roof_type" ADD VALUE 'Pitched, sloping ceiling, 225 mm insulation' BEFORE 'Roof room(s), insulated';--> statement-breakpoint +ALTER TYPE "public"."roof_type" ADD VALUE 'Pitched, sloping ceiling, 250 mm insulation' BEFORE 'Roof room(s), insulated';--> statement-breakpoint +ALTER TYPE "public"."roof_type" ADD VALUE 'Pitched, sloping ceiling, 270 mm insulation' BEFORE 'Roof room(s), insulated';--> statement-breakpoint +ALTER TYPE "public"."roof_type" ADD VALUE 'Pitched, sloping ceiling, 300 mm insulation' BEFORE 'Roof room(s), insulated';--> statement-breakpoint +ALTER TYPE "public"."roof_type" ADD VALUE 'Pitched, sloping ceiling, 350 mm insulation' BEFORE 'Roof room(s), insulated';--> statement-breakpoint +ALTER TYPE "public"."roof_type" ADD VALUE 'Pitched, sloping ceiling, 400 mm insulation' BEFORE 'Roof room(s), insulated';--> statement-breakpoint +ALTER TYPE "public"."roof_type" ADD VALUE 'Pitched, sloping ceiling, 400+ mm insulation' BEFORE 'Roof room(s), insulated'; \ No newline at end of file diff --git a/src/app/db/migrations/0279_blushing_mattie_franklin.sql b/src/app/db/migrations/0279_blushing_mattie_franklin.sql new file mode 100644 index 00000000..4d53c92f --- /dev/null +++ b/src/app/db/migrations/0279_blushing_mattie_franklin.sql @@ -0,0 +1,3 @@ +ALTER TYPE "public"."main_heating_system" ADD VALUE 'Oil boiler, regular' BEFORE 'Electric storage heaters, old';--> statement-breakpoint +ALTER TYPE "public"."main_heating_system" ADD VALUE 'Oil boiler, combi' BEFORE 'Electric storage heaters, old';--> statement-breakpoint +ALTER TYPE "public"."main_heating_system" ADD VALUE 'Solid fuel boiler' BEFORE 'Electric storage heaters, old'; \ No newline at end of file diff --git a/src/app/db/migrations/0280_flashy_dreadnoughts.sql b/src/app/db/migrations/0280_flashy_dreadnoughts.sql new file mode 100644 index 00000000..fa3b4815 --- /dev/null +++ b/src/app/db/migrations/0280_flashy_dreadnoughts.sql @@ -0,0 +1,23 @@ +-- work_order.priority: text -> boolean (#419). +-- +-- Hand-edited after `drizzle-kit generate`, which emitted only the SET DATA +-- TYPE and SET NOT NULL statements. Two corrections, both needed: +-- +-- 1. Postgres refuses to cast text -> boolean implicitly, so the bare +-- `SET DATA TYPE boolean` fails with "column priority cannot be cast +-- automatically to type boolean". The USING clause below is that cast. +-- 2. drizzle-kit dropped the column's `DEFAULT false` from the SQL while +-- recording it in 0280_snapshot.json. Left as generated, the database +-- would end up NOT NULL with no default while drizzle believed a default +-- existed — so no later diff would ever add it, and an insert that omits +-- priority would fail. +-- +-- work_order held 0 rows when this was written, so the cast evaluates nothing +-- and the backfill is a no-op. Both are kept anyway for the case where the +-- programme import (#417) lands rows before this migration is applied: a +-- priority value that is not castable to boolean should fail the migration +-- loudly rather than be coerced into a wrong answer. +ALTER TABLE "work_order" ALTER COLUMN "priority" SET DATA TYPE boolean USING "priority"::boolean;--> statement-breakpoint +UPDATE "work_order" SET "priority" = false WHERE "priority" IS NULL;--> statement-breakpoint +ALTER TABLE "work_order" ALTER COLUMN "priority" SET DEFAULT false;--> statement-breakpoint +ALTER TABLE "work_order" ALTER COLUMN "priority" SET NOT NULL; diff --git a/src/app/db/migrations/meta/0276_snapshot.json b/src/app/db/migrations/meta/0276_snapshot.json new file mode 100644 index 00000000..aabaaba9 --- /dev/null +++ b/src/app/db/migrations/meta/0276_snapshot.json @@ -0,0 +1,13484 @@ +{ + "id": "e5296a66-470c-46da-8a10-8149852ef94c", + "prevId": "6434db4f-1fd0-48c8-9f40-db8dfac7160d", + "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()" + }, + "last_updated_at": { + "name": "last_updated_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.deal_measure_approval_events": { + "name": "deal_measure_approval_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "acted_by": { + "name": "acted_by", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "acted_at": { + "name": "acted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_deal_measure_events_deal_id": { + "name": "idx_deal_measure_events_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_deal_measure_events_acted_at": { + "name": "idx_deal_measure_events_acted_at", + "columns": [ + { + "expression": "acted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deal_measure_approval_events_acted_by_user_id_fk": { + "name": "deal_measure_approval_events_acted_by_user_id_fk", + "tableFrom": "deal_measure_approval_events", + "tableTo": "user", + "columnsFrom": [ + "acted_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deal_measure_approvals": { + "name": "deal_measure_approvals", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_approved": { + "name": "is_approved", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "approved_by": { + "name": "approved_by", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "approved_at": { + "name": "approved_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_deal_measure_approvals_deal_id": { + "name": "idx_deal_measure_approvals_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deal_measure_approvals_approved_by_user_id_fk": { + "name": "deal_measure_approvals_approved_by_user_id_fk", + "tableFrom": "deal_measure_approvals", + "tableTo": "user", + "columnsFrom": [ + "approved_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "uq_deal_measure": { + "name": "uq_deal_measure", + "nullsNotDistinct": false, + "columns": [ + "hubspot_deal_id", + "measure_name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bulk_address_uploads": { + "name": "bulk_address_uploads", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "s3_bucket": { + "name": "s3_bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "s3_key": { + "name": "s3_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "filename": { + "name": "filename", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'ready_for_processing'" + }, + "source_headers": { + "name": "source_headers", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "column_mapping": { + "name": "column_mapping", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "multi_entry_summary": { + "name": "multi_entry_summary", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "multi_entry_ordering": { + "name": "multi_entry_ordering", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "verify_ack": { + "name": "verify_ack", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "task_id": { + "name": "task_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "combined_output_s3_uri": { + "name": "combined_output_s3_uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bulk_upload_uprn_corrections": { + "name": "bulk_upload_uprn_corrections", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "upload_id": { + "name": "upload_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "source_row_id": { + "name": "source_row_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address": { + "name": "address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "marked_no_uprn": { + "name": "marked_no_uprn", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "bulk_upload_uprn_corrections_upload_id_bulk_address_uploads_id_fk": { + "name": "bulk_upload_uprn_corrections_upload_id_bulk_address_uploads_id_fk", + "tableFrom": "bulk_upload_uprn_corrections", + "tableTo": "bulk_address_uploads", + "columnsFrom": [ + "upload_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "bulk_upload_uprn_corrections_upload_row_unique": { + "name": "bulk_upload_uprn_corrections_upload_row_unique", + "nullsNotDistinct": false, + "columns": [ + "upload_id", + "source_row_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.aspect_condition": { + "name": "aspect_condition", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "element_id": { + "name": "element_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "aspect_type": { + "name": "aspect_type", + "type": "aspect_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "aspect_instance": { + "name": "aspect_instance", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "quantity": { + "name": "quantity", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "install_date": { + "name": "install_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "renewal_year": { + "name": "renewal_year", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "comments": { + "name": "comments", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "aspect_condition_element_id_element_id_fk": { + "name": "aspect_condition_element_id_element_id_fk", + "tableFrom": "aspect_condition", + "tableTo": "element", + "columnsFrom": [ + "element_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.element": { + "name": "element", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "survey_id": { + "name": "survey_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "element_type": { + "name": "element_type", + "type": "element_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "element_instance": { + "name": "element_instance", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "element_survey_id_property_condition_survey_id_fk": { + "name": "element_survey_id_property_condition_survey_id_fk", + "tableFrom": "element", + "tableTo": "property_condition_survey", + "columnsFrom": [ + "survey_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_condition_survey": { + "name": "property_condition_survey", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "date": { + "name": "date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hubspot_company_data": { + "name": "hubspot_company_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "company_name": { + "name": "company_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "group_id": { + "name": "group_id", + "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": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hubspot_deal_data": { + "name": "hubspot_deal_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "deal_id": { + "name": "deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dealname": { + "name": "dealname", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dealstage": { + "name": "dealstage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "company_id": { + "name": "company_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "project_code": { + "name": "project_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "landlord_property_id": { + "name": "landlord_property_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "listing_id": { + "name": "listing_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uprn": { + "name": "uprn", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "outcome": { + "name": "outcome", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "outcome_notes": { + "name": "outcome_notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "major_condition_issue_description": { + "name": "major_condition_issue_description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "major_condition_issue_photos": { + "name": "major_condition_issue_photos", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "major_condition_issue_evidence_s3_url": { + "name": "major_condition_issue_evidence_s3_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "coordination_status": { + "name": "coordination_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "design_status": { + "name": "design_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "booking_status": { + "name": "booking_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pashub_link": { + "name": "pashub_link", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sharepoint_link": { + "name": "sharepoint_link", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dampmould_growth": { + "name": "dampmould_growth", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pre_sap": { + "name": "pre_sap", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "coordinator": { + "name": "coordinator", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mtp_completion_date": { + "name": "mtp_completion_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "mtp_re_model_completion_date": { + "name": "mtp_re_model_completion_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "ioe_v3_completion_date": { + "name": "ioe_v3_completion_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "proposed_measures": { + "name": "proposed_measures", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "approved_package": { + "name": "approved_package", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "designer": { + "name": "designer", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "design_type": { + "name": "design_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "design_completion_date": { + "name": "design_completion_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "actual_measures_installed": { + "name": "actual_measures_installed", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "installer": { + "name": "installer", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "installer_handover": { + "name": "installer_handover", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lodgement_status": { + "name": "lodgement_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "measures_lodgement_date": { + "name": "measures_lodgement_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "lodgement_date": { + "name": "lodgement_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "expected_commencement_date": { + "name": "expected_commencement_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "coordination_comments": { + "name": "coordination_comments", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "surveyor": { + "name": "surveyor", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "damp_mould_and_repairs_comments": { + "name": "damp_mould_and_repairs_comments", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "batch": { + "name": "batch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "batch_description": { + "name": "batch_description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "block_reference": { + "name": "block_reference", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "nonfunded_measures": { + "name": "nonfunded_measures", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_prn": { + "name": "epc_prn", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "potential_post_sap_score_dropdown": { + "name": "potential_post_sap_score_dropdown", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ei_score": { + "name": "ei_score", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ei_score__potential_": { + "name": "ei_score__potential_", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_sap_score": { + "name": "epc_sap_score", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_sap_score__potential_": { + "name": "epc_sap_score__potential_", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmed_survey_date": { + "name": "confirmed_survey_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "confirmed_survey_time": { + "name": "confirmed_survey_time", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "surveyed_date": { + "name": "surveyed_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "survey_type": { + "name": "survey_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "measures_for_pibi_ordered": { + "name": "measures_for_pibi_ordered", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pibi_order_date": { + "name": "pibi_order_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "pibi_completed_date": { + "name": "pibi_completed_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "property_halted_date": { + "name": "property_halted_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "property_halted_reason": { + "name": "property_halted_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "technical_approved_measures_for_install": { + "name": "technical_approved_measures_for_install", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sent_to_installer_for_pricing": { + "name": "sent_to_installer_for_pricing", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "domna_survey_required": { + "name": "domna_survey_required", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "domna_survey_type": { + "name": "domna_survey_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "domna_survey_date": { + "name": "domna_survey_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "date_booking_made": { + "name": "date_booking_made", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "last_contact_date": { + "name": "last_contact_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "last_outbound_call": { + "name": "last_outbound_call", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "last_outbound_email": { + "name": "last_outbound_email", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "last_submission_date": { + "name": "last_submission_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "number_of_attempts": { + "name": "number_of_attempts", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "client_booking_reference": { + "name": "client_booking_reference", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "third_party_surveyor_identifier": { + "name": "third_party_surveyor_identifier", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "design_constraints": { + "name": "design_constraints", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "planning_comments": { + "name": "planning_comments", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "planning_status": { + "name": "planning_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "planning_suggested_approach": { + "name": "planning_suggested_approach", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "planning_authority": { + "name": "planning_authority", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "designated_area": { + "name": "designated_area", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "article_4_pd_rights": { + "name": "article_4_pd_rights", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "listed_building": { + "name": "listed_building", + "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": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hubspot_projects_data": { + "name": "hubspot_projects_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "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": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "hubspot_projects_data_project_id_unique": { + "name": "hubspot_projects_data_project_id_unique", + "nullsNotDistinct": false, + "columns": [ + "project_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hubspot_users": { + "name": "hubspot_users", + "schema": "", + "columns": { + "hubspot_owner_id": { + "name": "hubspot_owner_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "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.epc_store": { + "name": "epc_store", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "epc_api_created_at": { + "name": "epc_api_created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "epc_api": { + "name": "epc_api", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "epc_page_created_at": { + "name": "epc_page_created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "epc_page": { + "name": "epc_page", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_page_rrn": { + "name": "epc_page_rrn", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "uq_epc_store_uprn": { + "name": "uq_epc_store_uprn", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.files_from_surveyor": { + "name": "files_from_surveyor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "s3_json_url": { + "name": "s3_json_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "files_from_surveyor_portfolio_id_portfolio_id_fk": { + "name": "files_from_surveyor_portfolio_id_portfolio_id_fk", + "tableFrom": "files_from_surveyor", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "files_from_surveyor_property_id_property_id_fk": { + "name": "files_from_surveyor_property_id_property_id_fk", + "tableFrom": "files_from_surveyor", + "tableTo": "property", + "columnsFrom": [ + "property_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.inspections": { + "name": "inspections", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "archetype": { + "name": "archetype", + "type": "inspection_archetype", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "archetype_2": { + "name": "archetype_2", + "type": "inspection_archetype_2", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "wall_construction": { + "name": "wall_construction", + "type": "inspections_wall_construction", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "insulation": { + "name": "insulation", + "type": "inspections_wall_insulation", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "insulation_material": { + "name": "insulation_material", + "type": "inspections_insulation_material", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "borescoped": { + "name": "borescoped", + "type": "inspection_borescoped", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "roof_orientation": { + "name": "roof_orientation", + "type": "inspections_roof_orientation", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "tile_hung": { + "name": "tile_hung", + "type": "inspections_tile_hung", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "rendered": { + "name": "rendered", + "type": "inspections_rendered", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "cladding": { + "name": "cladding", + "type": "inspections_cladding", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "access_issues": { + "name": "access_issues", + "type": "inspections_access_issues", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "surveyor_name": { + "name": "surveyor_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "inspections_property_id_property_id_fk": { + "name": "inspections_property_id_property_id_fk", + "tableFrom": "inspections", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_built_form_type_overrides": { + "name": "landlord_built_form_type_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "built_form_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_built_form_type_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_built_form_type_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_built_form_type_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_built_form_type_overrides_portfolio_description_unique": { + "name": "landlord_built_form_type_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_construction_age_band_overrides": { + "name": "landlord_construction_age_band_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "construction_age_band", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_construction_age_band_overrides_portfolio_fk": { + "name": "landlord_construction_age_band_overrides_portfolio_fk", + "tableFrom": "landlord_construction_age_band_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_construction_age_band_portfolio_description_unique": { + "name": "landlord_construction_age_band_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_glazing_overrides": { + "name": "landlord_glazing_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "glazing", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_glazing_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_glazing_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_glazing_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_glazing_overrides_portfolio_description_unique": { + "name": "landlord_glazing_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_main_fuel_overrides": { + "name": "landlord_main_fuel_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "main_fuel", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_main_fuel_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_main_fuel_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_main_fuel_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_main_fuel_overrides_portfolio_description_unique": { + "name": "landlord_main_fuel_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_main_heating_system_overrides": { + "name": "landlord_main_heating_system_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "main_heating_system", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_main_heating_system_overrides_portfolio_fk": { + "name": "landlord_main_heating_system_overrides_portfolio_fk", + "tableFrom": "landlord_main_heating_system_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_main_heating_system_portfolio_description_unique": { + "name": "landlord_main_heating_system_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_property_type_overrides": { + "name": "landlord_property_type_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "property_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_property_type_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_property_type_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_property_type_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_property_type_overrides_portfolio_description_unique": { + "name": "landlord_property_type_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_roof_type_overrides": { + "name": "landlord_roof_type_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "roof_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_roof_type_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_roof_type_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_roof_type_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_roof_type_overrides_portfolio_description_unique": { + "name": "landlord_roof_type_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_wall_type_overrides": { + "name": "landlord_wall_type_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "wall_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_wall_type_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_wall_type_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_wall_type_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_wall_type_overrides_portfolio_description_unique": { + "name": "landlord_wall_type_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_water_heating_overrides": { + "name": "landlord_water_heating_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "water_heating", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_water_heating_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_water_heating_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_water_heating_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_water_heating_overrides_portfolio_description_unique": { + "name": "landlord_water_heating_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_door_ventilation": { + "name": "magic_plan_door_ventilation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_door_id": { + "name": "magic_plan_door_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "undercut_mm": { + "name": "undercut_mm", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_door_ventilation_magic_plan_door_id_magic_plan_door_id_fk": { + "name": "magic_plan_door_ventilation_magic_plan_door_id_magic_plan_door_id_fk", + "tableFrom": "magic_plan_door_ventilation", + "tableTo": "magic_plan_door", + "columnsFrom": [ + "magic_plan_door_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "magic_plan_door_ventilation_magic_plan_door_id_unique": { + "name": "magic_plan_door_ventilation_magic_plan_door_id_unique", + "nullsNotDistinct": false, + "columns": [ + "magic_plan_door_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_door": { + "name": "magic_plan_door", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_room_id": { + "name": "magic_plan_room_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "width_mm": { + "name": "width_mm", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "height_mm": { + "name": "height_mm", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_door_magic_plan_room_id_magic_plan_room_id_fk": { + "name": "magic_plan_door_magic_plan_room_id_magic_plan_room_id_fk", + "tableFrom": "magic_plan_door", + "tableTo": "magic_plan_room", + "columnsFrom": [ + "magic_plan_room_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_floor": { + "name": "magic_plan_floor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_plan_id": { + "name": "magic_plan_plan_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "level": { + "name": "level", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_floor_magic_plan_plan_id_magic_plan_plan_id_fk": { + "name": "magic_plan_floor_magic_plan_plan_id_magic_plan_plan_id_fk", + "tableFrom": "magic_plan_floor", + "tableTo": "magic_plan_plan", + "columnsFrom": [ + "magic_plan_plan_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_plan": { + "name": "magic_plan_plan", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address": { + "name": "address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "magic_plan_uid": { + "name": "magic_plan_uid", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uploaded_file_id": { + "name": "uploaded_file_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_plan_uploaded_file_id_uploaded_files_id_fk": { + "name": "magic_plan_plan_uploaded_file_id_uploaded_files_id_fk", + "tableFrom": "magic_plan_plan", + "tableTo": "uploaded_files", + "columnsFrom": [ + "uploaded_file_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "magic_plan_plan_magic_plan_uid_unique": { + "name": "magic_plan_plan_magic_plan_uid_unique", + "nullsNotDistinct": false, + "columns": [ + "magic_plan_uid" + ] + }, + "magic_plan_plan_uploaded_file_id_unique": { + "name": "magic_plan_plan_uploaded_file_id_unique", + "nullsNotDistinct": false, + "columns": [ + "uploaded_file_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_room": { + "name": "magic_plan_room", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_floor_id": { + "name": "magic_plan_floor_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "width_m": { + "name": "width_m", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "length_m": { + "name": "length_m", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "area_m2": { + "name": "area_m2", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_room_magic_plan_floor_id_magic_plan_floor_id_fk": { + "name": "magic_plan_room_magic_plan_floor_id_magic_plan_floor_id_fk", + "tableFrom": "magic_plan_room", + "tableTo": "magic_plan_floor", + "columnsFrom": [ + "magic_plan_floor_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_window_ventilation": { + "name": "magic_plan_window_ventilation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_window_id": { + "name": "magic_plan_window_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "opening_type": { + "name": "opening_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "num_openings": { + "name": "num_openings", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "pct_openable": { + "name": "pct_openable", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "trickle_vent_area_mm2": { + "name": "trickle_vent_area_mm2", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "num_trickle_vents": { + "name": "num_trickle_vents", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_window_ventilation_magic_plan_window_id_magic_plan_window_id_fk": { + "name": "magic_plan_window_ventilation_magic_plan_window_id_magic_plan_window_id_fk", + "tableFrom": "magic_plan_window_ventilation", + "tableTo": "magic_plan_window", + "columnsFrom": [ + "magic_plan_window_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "magic_plan_window_ventilation_magic_plan_window_id_unique": { + "name": "magic_plan_window_ventilation_magic_plan_window_id_unique", + "nullsNotDistinct": false, + "columns": [ + "magic_plan_window_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_window": { + "name": "magic_plan_window", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_room_id": { + "name": "magic_plan_room_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "width_m": { + "name": "width_m", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "height_m": { + "name": "height_m", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "area_m2": { + "name": "area_m2", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_window_magic_plan_room_id_magic_plan_room_id_fk": { + "name": "magic_plan_window_magic_plan_room_id_magic_plan_room_id_fk", + "tableFrom": "magic_plan_window", + "tableTo": "magic_plan_room", + "columnsFrom": [ + "magic_plan_room_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": { + "idx_material_active": { + "name": "idx_material_active", + "columns": [ + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"material\".\"is_active\"", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organisation": { + "name": "organisation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "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()" + }, + "hubspot_company_id": { + "name": "hubspot_company_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pibi_requests": { + "name": "pibi_requests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "ordered_at": { + "name": "ordered_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "pushed_at": { + "name": "pushed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_pibi_requests_deal_id": { + "name": "idx_pibi_requests_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_pibi_requests_portfolio_id": { + "name": "idx_pibi_requests_portfolio_id", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pibi_requests_portfolio_id_portfolio_id_fk": { + "name": "pibi_requests_portfolio_id_portfolio_id_fk", + "tableFrom": "pibi_requests", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "pibi_requests_created_by_user_id_user_id_fk": { + "name": "pibi_requests_created_by_user_id_user_id_fk", + "tableFrom": "pibi_requests", + "tableTo": "user", + "columnsFrom": [ + "created_by_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.portfolio_organisation": { + "name": "portfolio_organisation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "organisation_id": { + "name": "organisation_id", + "type": "uuid", + "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": { + "portfolio_organisation_portfolio_id_portfolio_id_fk": { + "name": "portfolio_organisation_portfolio_id_portfolio_id_fk", + "tableFrom": "portfolio_organisation", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "portfolio_organisation_organisation_id_organisation_id_fk": { + "name": "portfolio_organisation_organisation_id_organisation_id_fk", + "tableFrom": "portfolio_organisation", + "tableTo": "organisation", + "columnsFrom": [ + "organisation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "portfolio_organisation_portfolio_id_organisation_id_unique": { + "name": "portfolio_organisation_portfolio_id_organisation_id_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "organisation_id" + ] + } + }, + "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.portfolio_capabilities": { + "name": "portfolio_capabilities", + "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 + }, + "capability": { + "name": "capability", + "type": "portfolio_capability", + "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": { + "portfolio_capabilities_user_id_user_id_fk": { + "name": "portfolio_capabilities_user_id_user_id_fk", + "tableFrom": "portfolio_capabilities", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "portfolio_capabilities_portfolio_id_portfolio_id_fk": { + "name": "portfolio_capabilities_portfolio_id_portfolio_id_fk", + "tableFrom": "portfolio_capabilities", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "portfolio_capabilities_user_id_portfolio_id_capability_unique": { + "name": "portfolio_capabilities_user_id_portfolio_id_capability_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "portfolio_id", + "capability" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.portfolioInvitations": { + "name": "portfolioInvitations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "invited_by_user_id": { + "name": "invited_by_user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "portfolioInvitations_portfolio_id_portfolio_id_fk": { + "name": "portfolioInvitations_portfolio_id_portfolio_id_fk", + "tableFrom": "portfolioInvitations", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "portfolioInvitations_invited_by_user_id_user_id_fk": { + "name": "portfolioInvitations_invited_by_user_id_user_id_fk", + "tableFrom": "portfolioInvitations", + "tableTo": "user", + "columnsFrom": [ + "invited_by_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "portfolio_invitations_portfolio_email_unique": { + "name": "portfolio_invitations_portfolio_email_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "email" + ] + } + }, + "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.project": { + "name": "project", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "organisation_id": { + "name": "organisation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "project_type_id": { + "name": "project_type_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start_date": { + "name": "start_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "end_date": { + "name": "end_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "domna_admin_access": { + "name": "domna_admin_access", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "sharepoint_base_url": { + "name": "sharepoint_base_url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "sharepoint_sub_folder_template": { + "name": "sharepoint_sub_folder_template", + "type": "varchar", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "project_organisation_id_organisation_id_fk": { + "name": "project_organisation_id_organisation_id_fk", + "tableFrom": "project", + "tableTo": "organisation", + "columnsFrom": [ + "organisation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_project_type_id_project_type_id_fk": { + "name": "project_project_type_id_project_type_id_fk", + "tableFrom": "project", + "tableTo": "project_type", + "columnsFrom": [ + "project_type_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_property": { + "name": "project_property", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "project_property_project_id_project_id_fk": { + "name": "project_property_project_id_project_id_fk", + "tableFrom": "project_property", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_property_property_id_property_id_fk": { + "name": "project_property_property_id_property_id_fk", + "tableFrom": "project_property", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "project_property_project_id_property_id_unique": { + "name": "project_property_project_id_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "project_id", + "property_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_type": { + "name": "project_type", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_workstream": { + "name": "project_workstream", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "workstream_id": { + "name": "workstream_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "current_stage_id": { + "name": "current_stage_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "project_workstream_project_id_project_id_fk": { + "name": "project_workstream_project_id_project_id_fk", + "tableFrom": "project_workstream", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_workstream_workstream_id_workstream_id_fk": { + "name": "project_workstream_workstream_id_workstream_id_fk", + "tableFrom": "project_workstream", + "tableTo": "workstream", + "columnsFrom": [ + "workstream_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_workstream_current_stage_id_project_workstream_stage_id_fk": { + "name": "project_workstream_current_stage_id_project_workstream_stage_id_fk", + "tableFrom": "project_workstream", + "tableTo": "project_workstream_stage", + "columnsFrom": [ + "current_stage_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_workstream_contractor": { + "name": "project_workstream_contractor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_workstream_id": { + "name": "project_workstream_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "organisation_id": { + "name": "organisation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "update_stages_permission": { + "name": "update_stages_permission", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "upload_documents_permission": { + "name": "upload_documents_permission", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "assigned_at": { + "name": "assigned_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "project_workstream_contractor_project_workstream_id_project_workstream_id_fk": { + "name": "project_workstream_contractor_project_workstream_id_project_workstream_id_fk", + "tableFrom": "project_workstream_contractor", + "tableTo": "project_workstream", + "columnsFrom": [ + "project_workstream_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_workstream_contractor_organisation_id_organisation_id_fk": { + "name": "project_workstream_contractor_organisation_id_organisation_id_fk", + "tableFrom": "project_workstream_contractor", + "tableTo": "organisation", + "columnsFrom": [ + "organisation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_workstream_evidence_requirement": { + "name": "project_workstream_evidence_requirement", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_workstream_id": { + "name": "project_workstream_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "file_type": { + "name": "file_type", + "type": "file_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "project_workstream_stage_id": { + "name": "project_workstream_stage_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "required": { + "name": "required", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "naming_rule": { + "name": "naming_rule", + "type": "varchar", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "project_workstream_evidence_requirement_project_workstream_id_project_workstream_id_fk": { + "name": "project_workstream_evidence_requirement_project_workstream_id_project_workstream_id_fk", + "tableFrom": "project_workstream_evidence_requirement", + "tableTo": "project_workstream", + "columnsFrom": [ + "project_workstream_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_workstream_evidence_requirement_project_workstream_stage_id_project_workstream_stage_id_fk": { + "name": "project_workstream_evidence_requirement_project_workstream_stage_id_project_workstream_stage_id_fk", + "tableFrom": "project_workstream_evidence_requirement", + "tableTo": "project_workstream_stage", + "columnsFrom": [ + "project_workstream_stage_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_workstream_stage": { + "name": "project_workstream_stage", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_workstream_id": { + "name": "project_workstream_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "start_date": { + "name": "start_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "due_date": { + "name": "due_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "last_updated": { + "name": "last_updated", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status_description": { + "name": "status_description", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "project_workstream_stage_project_workstream_id_project_workstream_id_fk": { + "name": "project_workstream_stage_project_workstream_id_project_workstream_id_fk", + "tableFrom": "project_workstream_stage", + "tableTo": "project_workstream", + "columnsFrom": [ + "project_workstream_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.work_order": { + "name": "work_order", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "reference": { + "name": "reference", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "project_workstream_contractor_id": { + "name": "project_workstream_contractor_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "project_workstream_stage_id": { + "name": "project_workstream_stage_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "forecast_end": { + "name": "forecast_end", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "priority": { + "name": "priority", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "work_order_project_workstream_contractor_id_project_workstream_contractor_id_fk": { + "name": "work_order_project_workstream_contractor_id_project_workstream_contractor_id_fk", + "tableFrom": "work_order", + "tableTo": "project_workstream_contractor", + "columnsFrom": [ + "project_workstream_contractor_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "work_order_property_id_property_id_fk": { + "name": "work_order_property_id_property_id_fk", + "tableFrom": "work_order", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "work_order_project_workstream_stage_id_project_workstream_stage_id_fk": { + "name": "work_order_project_workstream_stage_id_project_workstream_stage_id_fk", + "tableFrom": "work_order", + "tableTo": "project_workstream_stage", + "columnsFrom": [ + "project_workstream_stage_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "work_order_reference_unique": { + "name": "work_order_reference_unique", + "nullsNotDistinct": false, + "columns": [ + "reference" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workstream": { + "name": "workstream", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_overrides": { + "name": "property_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "building_part": { + "name": "building_part", + "type": "smallint", + "primaryKey": false, + "notNull": true + }, + "override_component": { + "name": "override_component", + "type": "override_component", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "override_value": { + "name": "override_value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "original_spreadsheet_description": { + "name": "original_spreadsheet_description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "property_overrides_property_id_property_id_fk": { + "name": "property_overrides_property_id_property_id_fk", + "tableFrom": "property_overrides", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "property_overrides_portfolio_id_portfolio_id_fk": { + "name": "property_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "property_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "property_overrides_property_component_part_unique": { + "name": "property_overrides_property_component_part_unique", + "nullsNotDistinct": false, + "columns": [ + "property_id", + "override_component", + "building_part" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_building_part": { + "name": "epc_building_part", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "construction_age_band": { + "name": "construction_age_band", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "wall_construction": { + "name": "wall_construction", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "wall_insulation_type": { + "name": "wall_insulation_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "wall_thickness_measured": { + "name": "wall_thickness_measured", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "party_wall_construction": { + "name": "party_wall_construction", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "building_part_number": { + "name": "building_part_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "wall_dry_lined": { + "name": "wall_dry_lined", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "wall_thickness_mm": { + "name": "wall_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "wall_insulation_thickness": { + "name": "wall_insulation_thickness", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "wall_insulation_thermal_conductivity": { + "name": "wall_insulation_thermal_conductivity", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "floor_heat_loss": { + "name": "floor_heat_loss", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "floor_insulation_thickness": { + "name": "floor_insulation_thickness", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "flat_roof_insulation_thickness": { + "name": "flat_roof_insulation_thickness", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "floor_type": { + "name": "floor_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "floor_construction_type": { + "name": "floor_construction_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "floor_insulation_type_str": { + "name": "floor_insulation_type_str", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "floor_u_value_known": { + "name": "floor_u_value_known", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "roof_construction": { + "name": "roof_construction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "roof_insulation_location": { + "name": "roof_insulation_location", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "roof_insulation_thickness": { + "name": "roof_insulation_thickness", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "rafter_insulation_thickness": { + "name": "rafter_insulation_thickness", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "roof_construction_type": { + "name": "roof_construction_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "curtain_wall_age": { + "name": "curtain_wall_age", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "wall_is_basement": { + "name": "wall_is_basement", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "wall_u_value": { + "name": "wall_u_value", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "room_in_roof_floor_area": { + "name": "room_in_roof_floor_area", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "room_in_roof_construction_age_band": { + "name": "room_in_roof_construction_age_band", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_area": { + "name": "alt_wall_1_area", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_dry_lined": { + "name": "alt_wall_1_dry_lined", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_construction": { + "name": "alt_wall_1_construction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_insulation_type": { + "name": "alt_wall_1_insulation_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_thickness_measured": { + "name": "alt_wall_1_thickness_measured", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_insulation_thickness": { + "name": "alt_wall_1_insulation_thickness", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_is_sheltered": { + "name": "alt_wall_1_is_sheltered", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_u_value": { + "name": "alt_wall_1_u_value", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_thickness_mm": { + "name": "alt_wall_1_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_is_basement": { + "name": "alt_wall_1_is_basement", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_area": { + "name": "alt_wall_2_area", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_dry_lined": { + "name": "alt_wall_2_dry_lined", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_construction": { + "name": "alt_wall_2_construction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_insulation_type": { + "name": "alt_wall_2_insulation_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_thickness_measured": { + "name": "alt_wall_2_thickness_measured", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_insulation_thickness": { + "name": "alt_wall_2_insulation_thickness", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_is_sheltered": { + "name": "alt_wall_2_is_sheltered", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_u_value": { + "name": "alt_wall_2_u_value", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_thickness_mm": { + "name": "alt_wall_2_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_is_basement": { + "name": "alt_wall_2_is_basement", + "type": "boolean", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "ix_epc_building_part_epc_property": { + "name": "ix_epc_building_part_epc_property", + "columns": [ + { + "expression": "epc_property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_building_part_epc_property_id_epc_property_id_fk": { + "name": "epc_building_part_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_building_part", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_energy_element": { + "name": "epc_energy_element", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "element_type": { + "name": "element_type", + "type": "energy_element_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "energy_efficiency_rating": { + "name": "energy_efficiency_rating", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "environmental_efficiency_rating": { + "name": "environmental_efficiency_rating", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "ix_epc_energy_element_epc_property": { + "name": "ix_epc_energy_element_epc_property", + "columns": [ + { + "expression": "epc_property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_energy_element_epc_property_id_epc_property_id_fk": { + "name": "epc_energy_element_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_energy_element", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_flat_details": { + "name": "epc_flat_details", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "level": { + "name": "level", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "top_storey": { + "name": "top_storey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "flat_location": { + "name": "flat_location", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "heat_loss_corridor": { + "name": "heat_loss_corridor", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "storey_count": { + "name": "storey_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "unheated_corridor_length_m": { + "name": "unheated_corridor_length_m", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_flat_details_epc_property_id_epc_property_id_fk": { + "name": "epc_flat_details_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_flat_details", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_flat_details_epc_property_id_unique": { + "name": "epc_flat_details_epc_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "epc_property_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_floor_dimension": { + "name": "epc_floor_dimension", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_building_part_id": { + "name": "epc_building_part_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "floor": { + "name": "floor", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "room_height_m": { + "name": "room_height_m", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "total_floor_area_m2": { + "name": "total_floor_area_m2", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "party_wall_length_m": { + "name": "party_wall_length_m", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "heat_loss_perimeter_m": { + "name": "heat_loss_perimeter_m", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "floor_insulation": { + "name": "floor_insulation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "floor_construction": { + "name": "floor_construction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "is_exposed_floor": { + "name": "is_exposed_floor", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_above_partially_heated_space": { + "name": "is_above_partially_heated_space", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "ix_epc_floor_dimension_building_part": { + "name": "ix_epc_floor_dimension_building_part", + "columns": [ + { + "expression": "epc_building_part_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_floor_dimension_epc_building_part_id_epc_building_part_id_fk": { + "name": "epc_floor_dimension_epc_building_part_id_epc_building_part_id_fk", + "tableFrom": "epc_floor_dimension", + "tableTo": "epc_building_part", + "columnsFrom": [ + "epc_building_part_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_main_heating_detail": { + "name": "epc_main_heating_detail", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "has_fghrs": { + "name": "has_fghrs", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "main_fuel_type": { + "name": "main_fuel_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "heat_emitter_type": { + "name": "heat_emitter_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "emitter_temperature": { + "name": "emitter_temperature", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "main_heating_control": { + "name": "main_heating_control", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "fan_flue_present": { + "name": "fan_flue_present", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "boiler_flue_type": { + "name": "boiler_flue_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "boiler_ignition_type": { + "name": "boiler_ignition_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "central_heating_pump_age": { + "name": "central_heating_pump_age", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "central_heating_pump_age_str": { + "name": "central_heating_pump_age_str", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "main_heating_index_number": { + "name": "main_heating_index_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "sap_main_heating_code": { + "name": "sap_main_heating_code", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "main_heating_number": { + "name": "main_heating_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "main_heating_category": { + "name": "main_heating_category", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "main_heating_fraction": { + "name": "main_heating_fraction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "main_heating_data_source": { + "name": "main_heating_data_source", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "condensing": { + "name": "condensing", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "weather_compensator": { + "name": "weather_compensator", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "community_heating_boiler_fuel_type": { + "name": "community_heating_boiler_fuel_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "community_heating_chp_fraction": { + "name": "community_heating_chp_fraction", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "ix_epc_main_heating_detail_epc_property": { + "name": "ix_epc_main_heating_detail_epc_property", + "columns": [ + { + "expression": "epc_property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_main_heating_detail_epc_property_id_epc_property_id_fk": { + "name": "epc_main_heating_detail_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_main_heating_detail", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_photovoltaic_array": { + "name": "epc_photovoltaic_array", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "array_index": { + "name": "array_index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "peak_power": { + "name": "peak_power", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "pitch": { + "name": "pitch", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "overshading": { + "name": "overshading", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "orientation": { + "name": "orientation", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_photovoltaic_array_epc_property_id_epc_property_id_fk": { + "name": "epc_photovoltaic_array_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_photovoltaic_array", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_property": { + "name": "epc_property", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "uploaded_file_id": { + "name": "uploaded_file_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'lodged'" + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "uprn_source": { + "name": "uprn_source", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "report_reference": { + "name": "report_reference", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "report_type": { + "name": "report_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "assessment_type": { + "name": "assessment_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sap_version": { + "name": "sap_version", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "schema_type": { + "name": "schema_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "schema_versions_original": { + "name": "schema_versions_original", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "calculation_software_version": { + "name": "calculation_software_version", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address_line_1": { + "name": "address_line_1", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "address_line_2": { + "name": "address_line_2", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "post_town": { + "name": "post_town", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "region_code": { + "name": "region_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "country_code": { + "name": "country_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "language_code": { + "name": "language_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dwelling_type": { + "name": "dwelling_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "property_type": { + "name": "property_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "built_form": { + "name": "built_form", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tenure": { + "name": "tenure", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "transaction_type": { + "name": "transaction_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "inspection_date": { + "name": "inspection_date", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "completion_date": { + "name": "completion_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "registration_date": { + "name": "registration_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "total_floor_area_m2": { + "name": "total_floor_area_m2", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "measurement_type": { + "name": "measurement_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "solar_water_heating": { + "name": "solar_water_heating", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "has_hot_water_cylinder": { + "name": "has_hot_water_cylinder", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "has_fixed_air_conditioning": { + "name": "has_fixed_air_conditioning", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "has_conservatory": { + "name": "has_conservatory", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "has_heated_separate_conservatory": { + "name": "has_heated_separate_conservatory", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "conservatory_type": { + "name": "conservatory_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "conservatory_floor_area_m2": { + "name": "conservatory_floor_area_m2", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "conservatory_glazed_perimeter_m": { + "name": "conservatory_glazed_perimeter_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "conservatory_double_glazed": { + "name": "conservatory_double_glazed", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "conservatory_thermally_separated": { + "name": "conservatory_thermally_separated", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "conservatory_room_height_storeys": { + "name": "conservatory_room_height_storeys", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "door_count": { + "name": "door_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "wet_rooms_count": { + "name": "wet_rooms_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "extensions_count": { + "name": "extensions_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "heated_rooms_count": { + "name": "heated_rooms_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "open_chimneys_count": { + "name": "open_chimneys_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "habitable_rooms_count": { + "name": "habitable_rooms_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "insulated_door_count": { + "name": "insulated_door_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "cfl_fixed_lighting_bulbs_count": { + "name": "cfl_fixed_lighting_bulbs_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "led_fixed_lighting_bulbs_count": { + "name": "led_fixed_lighting_bulbs_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "incandescent_fixed_lighting_bulbs_count": { + "name": "incandescent_fixed_lighting_bulbs_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "blocked_chimneys_count": { + "name": "blocked_chimneys_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "draughtproofed_door_count": { + "name": "draughtproofed_door_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "energy_rating_average": { + "name": "energy_rating_average", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "low_energy_fixed_lighting_bulbs_count": { + "name": "low_energy_fixed_lighting_bulbs_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "fixed_lighting_outlets_count": { + "name": "fixed_lighting_outlets_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "low_energy_fixed_lighting_outlets_count": { + "name": "low_energy_fixed_lighting_outlets_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "number_of_storeys": { + "name": "number_of_storeys", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "any_unheated_rooms": { + "name": "any_unheated_rooms", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "hydro": { + "name": "hydro", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "photovoltaic_array": { + "name": "photovoltaic_array", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "waste_water_heat_recovery": { + "name": "waste_water_heat_recovery", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pressure_test": { + "name": "pressure_test", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "pressure_test_certificate_number": { + "name": "pressure_test_certificate_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "percent_draughtproofed": { + "name": "percent_draughtproofed", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "insulated_door_u_value": { + "name": "insulated_door_u_value", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "multiple_glazed_proportion": { + "name": "multiple_glazed_proportion", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "windows_transmission_u_value": { + "name": "windows_transmission_u_value", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "windows_transmission_data_source": { + "name": "windows_transmission_data_source", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "windows_transmission_solar_transmittance": { + "name": "windows_transmission_solar_transmittance", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_gas_connection_available": { + "name": "energy_gas_connection_available", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "energy_meter_type": { + "name": "energy_meter_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "energy_pv_battery_count": { + "name": "energy_pv_battery_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "energy_wind_turbines_count": { + "name": "energy_wind_turbines_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "energy_gas_smart_meter_present": { + "name": "energy_gas_smart_meter_present", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "energy_is_dwelling_export_capable": { + "name": "energy_is_dwelling_export_capable", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "energy_wind_turbines_terrain_type": { + "name": "energy_wind_turbines_terrain_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "energy_electricity_smart_meter_present": { + "name": "energy_electricity_smart_meter_present", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "energy_pv_connection": { + "name": "energy_pv_connection", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "energy_pv_percent_roof_area": { + "name": "energy_pv_percent_roof_area", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "energy_pv_battery_capacity": { + "name": "energy_pv_battery_capacity", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_wind_turbine_hub_height": { + "name": "energy_wind_turbine_hub_height", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_wind_turbine_rotor_diameter": { + "name": "energy_wind_turbine_rotor_diameter", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_pv_diverter_present": { + "name": "energy_pv_diverter_present", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "heating_cylinder_size": { + "name": "heating_cylinder_size", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_water_heating_code": { + "name": "heating_water_heating_code", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_water_heating_fuel": { + "name": "heating_water_heating_fuel", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_immersion_heating_type": { + "name": "heating_immersion_heating_type", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_insulation_type": { + "name": "heating_cylinder_insulation_type", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_thermostat": { + "name": "heating_cylinder_thermostat", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "heating_secondary_fuel_type": { + "name": "heating_secondary_fuel_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_secondary_heating_type": { + "name": "heating_secondary_heating_type", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_insulation_thickness_mm": { + "name": "heating_cylinder_insulation_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_volume_measured_l": { + "name": "heating_cylinder_volume_measured_l", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_heat_loss": { + "name": "heating_cylinder_heat_loss", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "heating_wwhrs_index_number_1": { + "name": "heating_wwhrs_index_number_1", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_wwhrs_index_number_2": { + "name": "heating_wwhrs_index_number_2", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_shower_outlet_type": { + "name": "heating_shower_outlet_type", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_shower_wwhrs": { + "name": "heating_shower_wwhrs", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_type": { + "name": "ventilation_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ventilation_draught_lobby": { + "name": "ventilation_draught_lobby", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "ventilation_pressure_test": { + "name": "ventilation_pressure_test", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ventilation_open_flues_count": { + "name": "ventilation_open_flues_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_closed_flues_count": { + "name": "ventilation_closed_flues_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_boiler_flues_count": { + "name": "ventilation_boiler_flues_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_other_flues_count": { + "name": "ventilation_other_flues_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_extract_fans_count": { + "name": "ventilation_extract_fans_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_passive_vents_count": { + "name": "ventilation_passive_vents_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_flueless_gas_fires_count": { + "name": "ventilation_flueless_gas_fires_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_in_pcdf_database": { + "name": "ventilation_in_pcdf_database", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "mechanical_ventilation": { + "name": "mechanical_ventilation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_duct_type": { + "name": "mechanical_vent_duct_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_duct_placement": { + "name": "mechanical_vent_duct_placement", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_duct_insulation": { + "name": "mechanical_vent_duct_insulation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_ventilation_index_number": { + "name": "mechanical_ventilation_index_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_measured_installation": { + "name": "mechanical_vent_measured_installation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_duct_insulation_level": { + "name": "mechanical_vent_duct_insulation_level", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "addendum_stone_walls": { + "name": "addendum_stone_walls", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "addendum_system_build": { + "name": "addendum_system_build", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "addendum_numbers": { + "name": "addendum_numbers", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_number_baths": { + "name": "heating_number_baths", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_number_baths_wwhrs": { + "name": "heating_number_baths_wwhrs", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_electric_shower_count": { + "name": "heating_electric_shower_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_mixer_shower_count": { + "name": "heating_mixer_shower_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_present": { + "name": "ventilation_present", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "ventilation_sheltered_sides": { + "name": "ventilation_sheltered_sides", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_has_suspended_timber_floor": { + "name": "ventilation_has_suspended_timber_floor", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "ventilation_suspended_timber_floor_sealed": { + "name": "ventilation_suspended_timber_floor_sealed", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "ventilation_has_draught_lobby": { + "name": "ventilation_has_draught_lobby", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "ventilation_air_permeability_ap4_m3_h_m2": { + "name": "ventilation_air_permeability_ap4_m3_h_m2", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "ventilation_air_permeability_ap50_m3_h_m2": { + "name": "ventilation_air_permeability_ap50_m3_h_m2", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "ventilation_mechanical_ventilation_kind": { + "name": "ventilation_mechanical_ventilation_kind", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "uq_epc_property_property_portfolio": { + "name": "uq_epc_property_property_portfolio", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "ix_epc_property_property_source": { + "name": "ix_epc_property_property_source", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_property_property_id_property_id_fk": { + "name": "epc_property_property_id_property_id_fk", + "tableFrom": "epc_property", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "epc_property_portfolio_id_portfolio_id_fk": { + "name": "epc_property_portfolio_id_portfolio_id_fk", + "tableFrom": "epc_property", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "epc_property_uploaded_file_id_uploaded_files_id_fk": { + "name": "epc_property_uploaded_file_id_uploaded_files_id_fk", + "tableFrom": "epc_property", + "tableTo": "uploaded_files", + "columnsFrom": [ + "uploaded_file_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_property_uploaded_file_id_unique": { + "name": "epc_property_uploaded_file_id_unique", + "nullsNotDistinct": false, + "columns": [ + "uploaded_file_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_property_energy_performance": { + "name": "epc_property_energy_performance", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "energy_rating_current": { + "name": "energy_rating_current", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "energy_consumption_current": { + "name": "energy_consumption_current", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "environmental_impact_current": { + "name": "environmental_impact_current", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_cost_current": { + "name": "heating_cost_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lighting_cost_current": { + "name": "lighting_cost_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "hot_water_cost_current": { + "name": "hot_water_cost_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_emissions_current": { + "name": "co2_emissions_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_emissions_current_per_floor_area": { + "name": "co2_emissions_current_per_floor_area", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "current_energy_efficiency_band": { + "name": "current_energy_efficiency_band", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "energy_rating_potential": { + "name": "energy_rating_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_consumption_potential": { + "name": "energy_consumption_potential", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "environmental_impact_potential": { + "name": "environmental_impact_potential", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_cost_potential": { + "name": "heating_cost_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lighting_cost_potential": { + "name": "lighting_cost_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "hot_water_cost_potential": { + "name": "hot_water_cost_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_emissions_potential": { + "name": "co2_emissions_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "potential_energy_efficiency_band": { + "name": "potential_energy_efficiency_band", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_property_energy_performance_epc_property_id_epc_property_id_fk": { + "name": "epc_property_energy_performance_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_property_energy_performance", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_property_energy_performance_epc_property_id_unique": { + "name": "epc_property_energy_performance_epc_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "epc_property_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_renewable_heat_incentive": { + "name": "epc_renewable_heat_incentive", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "space_heating_kwh": { + "name": "space_heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "water_heating_kwh": { + "name": "water_heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "impact_of_loft_insulation_kwh": { + "name": "impact_of_loft_insulation_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "impact_of_cavity_insulation_kwh": { + "name": "impact_of_cavity_insulation_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "impact_of_solid_wall_insulation_kwh": { + "name": "impact_of_solid_wall_insulation_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_renewable_heat_incentive_epc_property_id_epc_property_id_fk": { + "name": "epc_renewable_heat_incentive_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_renewable_heat_incentive", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_renewable_heat_incentive_epc_property_id_unique": { + "name": "epc_renewable_heat_incentive_epc_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "epc_property_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_roof_window": { + "name": "epc_roof_window", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "roof_window_index": { + "name": "roof_window_index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "area_m2": { + "name": "area_m2", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "u_value_raw": { + "name": "u_value_raw", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "orientation": { + "name": "orientation", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "pitch_deg": { + "name": "pitch_deg", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "g_perpendicular": { + "name": "g_perpendicular", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "frame_factor": { + "name": "frame_factor", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "glazing_type": { + "name": "glazing_type", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "window_location": { + "name": "window_location", + "type": "jsonb", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "uq_epc_roof_window_property_index": { + "name": "uq_epc_roof_window_property_index", + "columns": [ + { + "expression": "epc_property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "roof_window_index", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_roof_window_epc_property_id_epc_property_id_fk": { + "name": "epc_roof_window_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_roof_window", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_room_in_roof": { + "name": "epc_room_in_roof", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_building_part_id": { + "name": "epc_building_part_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "floor_area": { + "name": "floor_area", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "construction_age_band": { + "name": "construction_age_band", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "common_wall_length_m": { + "name": "common_wall_length_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "common_wall_height_m": { + "name": "common_wall_height_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "gable_1_length_m": { + "name": "gable_1_length_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "gable_1_height_m": { + "name": "gable_1_height_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "gable_2_length_m": { + "name": "gable_2_length_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "gable_2_height_m": { + "name": "gable_2_height_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_room_in_roof_epc_building_part_id_epc_building_part_id_fk": { + "name": "epc_room_in_roof_epc_building_part_id_epc_building_part_id_fk", + "tableFrom": "epc_room_in_roof", + "tableTo": "epc_building_part", + "columnsFrom": [ + "epc_building_part_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_room_in_roof_epc_building_part_id_unique": { + "name": "epc_room_in_roof_epc_building_part_id_unique", + "nullsNotDistinct": false, + "columns": [ + "epc_building_part_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_room_in_roof_surface": { + "name": "epc_room_in_roof_surface", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_room_in_roof_id": { + "name": "epc_room_in_roof_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "surface_index": { + "name": "surface_index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "area_m2": { + "name": "area_m2", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "insulation_thickness_mm": { + "name": "insulation_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "insulation_type": { + "name": "insulation_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "u_value": { + "name": "u_value", + "type": "double precision", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "uq_epc_room_in_roof_surface_index": { + "name": "uq_epc_room_in_roof_surface_index", + "columns": [ + { + "expression": "epc_room_in_roof_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "surface_index", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_room_in_roof_surface_epc_room_in_roof_id_epc_room_in_roof_id_fk": { + "name": "epc_room_in_roof_surface_epc_room_in_roof_id_epc_room_in_roof_id_fk", + "tableFrom": "epc_room_in_roof_surface", + "tableTo": "epc_room_in_roof", + "columnsFrom": [ + "epc_room_in_roof_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_window": { + "name": "epc_window", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "glazing_gap": { + "name": "glazing_gap", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "orientation": { + "name": "orientation", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "window_type": { + "name": "window_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "glazing_type": { + "name": "glazing_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "window_width": { + "name": "window_width", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "window_height": { + "name": "window_height", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "draught_proofed": { + "name": "draught_proofed", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "window_location": { + "name": "window_location", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "window_wall_type": { + "name": "window_wall_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "permanent_shutters_present": { + "name": "permanent_shutters_present", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "frame_material": { + "name": "frame_material", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "frame_factor": { + "name": "frame_factor", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "permanent_shutters_insulated": { + "name": "permanent_shutters_insulated", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "transmission_u_value": { + "name": "transmission_u_value", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "transmission_data_source": { + "name": "transmission_data_source", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "transmission_solar_transmittance": { + "name": "transmission_solar_transmittance", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_window_epc_property_id_epc_property_id_fk": { + "name": "epc_window_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_window", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_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 + }, + "certificate_number": { + "name": "certificate_number", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "landlord_property_id": { + "name": "landlord_property_id", + "type": "text", + "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 + }, + "user_inputted_address": { + "name": "user_inputted_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_inputted_postcode": { + "name": "user_inputted_postcode", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lexiscore": { + "name": "lexiscore", + "type": "real", + "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 + }, + "installed_measures_sap_point_adjustment": { + "name": "installed_measures_sap_point_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "is_sap_points_adjusted_for_installed_measures": { + "name": "is_sap_points_adjusted_for_installed_measures", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "original_sap_points": { + "name": "original_sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lodged_sap_points": { + "name": "lodged_sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lodged_epc_rating": { + "name": "lodged_epc_rating", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "marked_for_deletion": { + "name": "marked_for_deletion", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "uq_property_portfolio_uprn": { + "name": "uq_property_portfolio_uprn", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"property\".\"uprn\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "ix_property_portfolio": { + "name": "ix_property_portfolio", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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_baseline_performance": { + "name": "property_baseline_performance", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "lodged_sap_score": { + "name": "lodged_sap_score", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "lodged_epc_band": { + "name": "lodged_epc_band", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "lodged_co2_emissions_t_per_yr": { + "name": "lodged_co2_emissions_t_per_yr", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lodged_primary_energy_intensity_kwh_per_m2_yr": { + "name": "lodged_primary_energy_intensity_kwh_per_m2_yr", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "effective_sap_score": { + "name": "effective_sap_score", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "effective_epc_band": { + "name": "effective_epc_band", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "effective_co2_emissions_t_per_yr": { + "name": "effective_co2_emissions_t_per_yr", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "effective_primary_energy_intensity_kwh_per_m2_yr": { + "name": "effective_primary_energy_intensity_kwh_per_m2_yr", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "rebaseline_reason": { + "name": "rebaseline_reason", + "type": "rebaseline_reason", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "space_heating_kwh": { + "name": "space_heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "water_heating_kwh": { + "name": "water_heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "fuel_rates_period": { + "name": "fuel_rates_period", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "heating_kwh": { + "name": "heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "heating_cost_gbp": { + "name": "heating_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "hot_water_kwh": { + "name": "hot_water_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "hot_water_cost_gbp": { + "name": "hot_water_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lighting_kwh": { + "name": "lighting_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lighting_cost_gbp": { + "name": "lighting_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "appliances_kwh": { + "name": "appliances_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "appliances_cost_gbp": { + "name": "appliances_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cooking_kwh": { + "name": "cooking_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cooking_cost_gbp": { + "name": "cooking_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "pumps_fans_kwh": { + "name": "pumps_fans_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "pumps_fans_cost_gbp": { + "name": "pumps_fans_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cooling_kwh": { + "name": "cooling_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cooling_cost_gbp": { + "name": "cooling_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "standing_charges_gbp": { + "name": "standing_charges_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "seg_credit_gbp": { + "name": "seg_credit_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "total_annual_bill_gbp": { + "name": "total_annual_bill_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "property_baseline_performance_property_id_property_id_fk": { + "name": "property_baseline_performance_property_id_property_id_fk", + "tableFrom": "property_baseline_performance", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "property_baseline_performance_property_id_unique": { + "name": "property_baseline_performance_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "property_id" + ] + } + }, + "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 + }, + "lodgement_date": { + "name": "lodgement_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "is_expired": { + "name": "is_expired", + "type": "boolean", + "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 + }, + "sap_05_overwritten": { + "name": "sap_05_overwritten", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "sap_05_score": { + "name": "sap_05_score", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "sap_05_epc_rating": { + "name": "sap_05_epc_rating", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": 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 + }, + "original_co2_emissions": { + "name": "original_co2_emissions", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "original_primary_energy_consumption": { + "name": "original_primary_energy_consumption", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "original_current_energy_demand": { + "name": "original_current_energy_demand", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "original_current_energy_demand_heating_hotwater": { + "name": "original_current_energy_demand_heating_hotwater", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "installed_measures_co2_adjustment": { + "name": "installed_measures_co2_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "installed_measures_energy_demand_adjustment": { + "name": "installed_measures_energy_demand_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "installed_measures_total_energy_bill_adjustment": { + "name": "installed_measures_total_energy_bill_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "installed_measures_heat_demand_adjustment": { + "name": "installed_measures_heat_demand_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "is_epc_adjusted_for_installed_measures": { + "name": "is_epc_adjusted_for_installed_measures", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "lodged_co2_emissions": { + "name": "lodged_co2_emissions", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lodged_heat_demand": { + "name": "lodged_heat_demand", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "has_been_remodelled": { + "name": "has_been_remodelled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "environment_impact_current": { + "name": "environment_impact_current", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "uq_property_details_epc_property_portfolio": { + "name": "uq_property_details_epc_property_portfolio", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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": { + "uq_property_details_spatial_uprn": { + "name": "uq_property_details_spatial_uprn", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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.installed_measure": { + "name": "installed_measure", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "measure_type": { + "name": "measure_type", + "type": "measure_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "installed_at": { + "name": "installed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "sap_points": { + "name": "sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "carbon_savings": { + "name": "carbon_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "kwh_savings": { + "name": "kwh_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "bill_savings": { + "name": "bill_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "heat_demand_savings": { + "name": "heat_demand_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + } + }, + "indexes": { + "idx_installed_measure_uprn": { + "name": "idx_installed_measure_uprn", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_installed_measure_uprn_active": { + "name": "idx_installed_measure_uprn_active", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"installed_measure\".\"is_active\" = true", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_installed_measure_measure_type": { + "name": "idx_installed_measure_measure_type", + "columns": [ + { + "expression": "measure_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_installed_measure_uprn_measure": { + "name": "idx_installed_measure_uprn_measure", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "measure_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"installed_measure\".\"is_active\" = true", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "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 + }, + "post_sap_points": { + "name": "post_sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "post_epc_rating": { + "name": "post_epc_rating", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "post_co2_emissions": { + "name": "post_co2_emissions", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_savings": { + "name": "co2_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "post_energy_bill": { + "name": "post_energy_bill", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_bill_savings": { + "name": "energy_bill_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "post_energy_consumption": { + "name": "post_energy_consumption", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_consumption_savings": { + "name": "energy_consumption_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "valuation_post_retrofit": { + "name": "valuation_post_retrofit", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "valuation_increase": { + "name": "valuation_increase", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cost_of_works": { + "name": "cost_of_works", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "contingency_cost": { + "name": "contingency_cost", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "plan_type": { + "name": "plan_type", + "type": "plan_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_plan_portfolio_scenario": { + "name": "idx_plan_portfolio_scenario", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scenario_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_plan_latest_per_property": { + "name": "idx_plan_latest_per_property", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scenario_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_plan_property_default_latest": { + "name": "idx_plan_property_default_latest", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "where": "is_default = true", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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": { + "idx_plan_recommendations_plan_id": { + "name": "idx_plan_recommendations_plan_id", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_plan_recommendations_plan_rec": { + "name": "idx_plan_recommendations_plan_rec", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "recommendation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_plan_recommendations_recommendation_id": { + "name": "idx_plan_recommendations_recommendation_id", + "columns": [ + { + "expression": "recommendation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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 + }, + "plan_id": { + "name": "plan_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "material_id": { + "name": "material_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "material_quantity": { + "name": "material_quantity", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "material_quantity_unit": { + "name": "material_quantity_unit", + "type": "unit_quantity", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "material_depth": { + "name": "material_depth", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "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": { + "recommendation_property_id_idx": { + "name": "recommendation_property_id_idx", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_plan_id": { + "name": "idx_recommendation_plan_id", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_active_defaults": { + "name": "idx_recommendation_active_defaults", + "columns": [ + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"recommendation\".\"default\" = true AND \"recommendation\".\"already_installed\" = false", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_active_id_property": { + "name": "idx_recommendation_active_id_property", + "columns": [ + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"recommendation\".\"default\" = true AND \"recommendation\".\"already_installed\" = false", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_plan_default": { + "name": "idx_recommendation_plan_default", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "measure_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "estimated_cost", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"recommendation\".\"default\" = true AND \"recommendation\".\"already_installed\" = false", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_material_id": { + "name": "idx_recommendation_material_id", + "columns": [ + { + "expression": "material_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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" + }, + "recommendation_plan_id_plan_id_fk": { + "name": "recommendation_plan_id_plan_id_fk", + "tableFrom": "recommendation", + "tableTo": "plan", + "columnsFrom": [ + "plan_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "recommendation_material_id_material_id_fk": { + "name": "recommendation_material_id_material_id_fk", + "tableFrom": "recommendation", + "tableTo": "material", + "columnsFrom": [ + "material_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "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": { + "recommendation_materials_recommendation_id_idx": { + "name": "recommendation_materials_recommendation_id_idx", + "columns": [ + { + "expression": "recommendation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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": "cascade", + "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 + }, + "fabric_first": { + "name": "fabric_first", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "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.property_removal_requests": { + "name": "property_removal_requests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'removal'" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "requested_by": { + "name": "requested_by", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "requested_at": { + "name": "requested_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "reviewed_by": { + "name": "reviewed_by", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "reviewed_at": { + "name": "reviewed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "original_batch": { + "name": "original_batch", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_removal_requests_deal_id": { + "name": "idx_removal_requests_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_removal_requests_portfolio_id": { + "name": "idx_removal_requests_portfolio_id", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "property_removal_requests_portfolio_id_portfolio_id_fk": { + "name": "property_removal_requests_portfolio_id_portfolio_id_fk", + "tableFrom": "property_removal_requests", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "property_removal_requests_requested_by_user_id_fk": { + "name": "property_removal_requests_requested_by_user_id_fk", + "tableFrom": "property_removal_requests", + "tableTo": "user", + "columnsFrom": [ + "requested_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "property_removal_requests_reviewed_by_user_id_fk": { + "name": "property_removal_requests_reviewed_by_user_id_fk", + "tableFrom": "property_removal_requests", + "tableTo": "user", + "columnsFrom": [ + "reviewed_by" + ], + "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.survey_requests": { + "name": "survey_requests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "survey_type": { + "name": "survey_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "requested_by": { + "name": "requested_by", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "requested_at": { + "name": "requested_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "fulfilled_at": { + "name": "fulfilled_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_survey_requests_deal_id": { + "name": "idx_survey_requests_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_survey_requests_portfolio_id": { + "name": "idx_survey_requests_portfolio_id", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "survey_requests_portfolio_id_portfolio_id_fk": { + "name": "survey_requests_portfolio_id_portfolio_id_fk", + "tableFrom": "survey_requests", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "survey_requests_requested_by_user_id_fk": { + "name": "survey_requests_requested_by_user_id_fk", + "tableFrom": "survey_requests", + "tableTo": "user", + "columnsFrom": [ + "requested_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.portfolio_tag": { + "name": "portfolio_tag", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "colour": { + "name": "colour", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "uq_portfolio_tag_portfolio_lower_name": { + "name": "uq_portfolio_tag_portfolio_lower_name", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"name\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "portfolio_tag_portfolio_id_portfolio_id_fk": { + "name": "portfolio_tag_portfolio_id_portfolio_id_fk", + "tableFrom": "portfolio_tag", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_tag": { + "name": "property_tag", + "schema": "", + "columns": { + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "tag_id": { + "name": "tag_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "ix_property_tag_tag": { + "name": "ix_property_tag_tag", + "columns": [ + { + "expression": "tag_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "property_tag_property_id_property_id_fk": { + "name": "property_tag_property_id_property_id_fk", + "tableFrom": "property_tag", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "property_tag_tag_id_portfolio_tag_id_fk": { + "name": "property_tag_tag_id_portfolio_tag_id_fk", + "tableFrom": "property_tag", + "tableTo": "portfolio_tag", + "columnsFrom": [ + "tag_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "property_tag_property_id_tag_id_pk": { + "name": "property_tag_property_id_tag_id_pk", + "columns": [ + "property_id", + "tag_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sub_task": { + "name": "sub_task", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "task_id": { + "name": "task_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "job_started": { + "name": "job_started", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "job_completed": { + "name": "job_completed", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'In Progress'" + }, + "service": { + "name": "service", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "inputs": { + "name": "inputs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "outputs": { + "name": "outputs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cloud_logs_url": { + "name": "cloud_logs_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "sub_task_task_id_tasks_id_fk": { + "name": "sub_task_task_id_tasks_id_fk", + "tableFrom": "sub_task", + "tableTo": "tasks", + "columnsFrom": [ + "task_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tasks": { + "name": "tasks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "task_source": { + "name": "task_source", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "job_started": { + "name": "job_started", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "job_completed": { + "name": "job_completed", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'In Progress'" + }, + "service": { + "name": "service", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "source", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "source_id": { + "name": "source_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "inputs": { + "name": "inputs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team": { + "name": "team", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "uuid", + "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": { + "team_org_id_organisation_id_fk": { + "name": "team_org_id_organisation_id_fk", + "tableFrom": "team", + "tableTo": "organisation", + "columnsFrom": [ + "org_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_members": { + "name": "team_members", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "team_id": { + "name": "team_id", + "type": "uuid", + "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": { + "team_members_user_id_user_id_fk": { + "name": "team_members_user_id_user_id_fk", + "tableFrom": "team_members", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "team_members_team_id_team_id_fk": { + "name": "team_members_team_id_team_id_fk", + "tableFrom": "team_members", + "tableTo": "team", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_portfolio_permissions": { + "name": "team_portfolio_permissions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "team_id": { + "name": "team_id", + "type": "uuid", + "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": { + "team_portfolio_permissions_team_id_team_id_fk": { + "name": "team_portfolio_permissions_team_id_team_id_fk", + "tableFrom": "team_portfolio_permissions", + "tableTo": "team", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "team_portfolio_permissions_portfolio_id_portfolio_id_fk": { + "name": "team_portfolio_permissions_portfolio_id_portfolio_id_fk", + "tableFrom": "team_portfolio_permissions", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.uploaded_files": { + "name": "uploaded_files", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "s3_file_bucket": { + "name": "s3_file_bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "s3_file_key": { + "name": "s3_file_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "s3_upload_timestamp": { + "name": "s3_upload_timestamp", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "landlord_property_id": { + "name": "landlord_property_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "hubspot_listing_id": { + "name": "hubspot_listing_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "file_type": { + "name": "file_type", + "type": "file_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "file_source": { + "name": "file_source", + "type": "file_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uploaded_by": { + "name": "uploaded_by", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "work_order_id": { + "name": "work_order_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "project_workstream_evidence_requirement_id": { + "name": "project_workstream_evidence_requirement_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "uploaded_files_uploaded_by_user_id_fk": { + "name": "uploaded_files_uploaded_by_user_id_fk", + "tableFrom": "uploaded_files", + "tableTo": "user", + "columnsFrom": [ + "uploaded_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "uploaded_files_work_order_id_work_order_id_fk": { + "name": "uploaded_files_work_order_id_work_order_id_fk", + "tableFrom": "uploaded_files", + "tableTo": "work_order", + "columnsFrom": [ + "work_order_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "uploaded_files_project_workstream_evidence_requirement_id_project_workstream_evidence_requirement_id_fk": { + "name": "uploaded_files_project_workstream_evidence_requirement_id_project_workstream_evidence_requirement_id_fk", + "tableFrom": "uploaded_files", + "tableTo": "project_workstream_evidence_requirement", + "columnsFrom": [ + "project_workstream_evidence_requirement_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_defined_deal_measures": { + "name": "user_defined_deal_measures", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "user_defined_deal_measure_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "pushed_at": { + "name": "pushed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "confirmed_in_hubspot_at": { + "name": "confirmed_in_hubspot_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_user_defined_deal_measures_deal_id": { + "name": "idx_user_defined_deal_measures_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_user_defined_deal_measures_source": { + "name": "idx_user_defined_deal_measures_source", + "columns": [ + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_defined_deal_measures_created_by_user_id_user_id_fk": { + "name": "user_defined_deal_measures_created_by_user_id_user_id_fk", + "tableFrom": "user_defined_deal_measures", + "tableTo": "user", + "columnsFrom": [ + "created_by_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_portfolio_config": { + "name": "user_portfolio_config", + "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 + }, + "starred_at": { + "name": "starred_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "folder_id": { + "name": "folder_id", + "type": "bigint", + "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": { + "idx_user_portfolio_config_folder": { + "name": "idx_user_portfolio_config_folder", + "columns": [ + { + "expression": "folder_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_portfolio_config_user_id_user_id_fk": { + "name": "user_portfolio_config_user_id_user_id_fk", + "tableFrom": "user_portfolio_config", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_portfolio_config_portfolio_id_portfolio_id_fk": { + "name": "user_portfolio_config_portfolio_id_portfolio_id_fk", + "tableFrom": "user_portfolio_config", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_portfolio_config_folder_owner_fk": { + "name": "user_portfolio_config_folder_owner_fk", + "tableFrom": "user_portfolio_config", + "tableTo": "user_portfolio_folders", + "columnsFrom": [ + "folder_id", + "user_id" + ], + "columnsTo": [ + "id", + "user_id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_portfolio_config_user_portfolio_unique": { + "name": "user_portfolio_config_user_portfolio_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "portfolio_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_portfolio_folders": { + "name": "user_portfolio_folders", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "position": { + "name": "position", + "type": "integer", + "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": { + "idx_user_portfolio_folders_user_position": { + "name": "idx_user_portfolio_folders_user_position", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "position", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_portfolio_folders_user_id_user_id_fk": { + "name": "user_portfolio_folders_user_id_user_id_fk", + "tableFrom": "user_portfolio_folders", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_portfolio_folders_id_user_unique": { + "name": "user_portfolio_folders_id_user_unique", + "nullsNotDistinct": false, + "columns": [ + "id", + "user_id" + ] + } + }, + "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.authRateLimits": { + "name": "authRateLimits", + "schema": "", + "columns": { + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "count": { + "name": "count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "window_start": { + "name": "window_start", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "authRateLimits_scope_key_pk": { + "name": "authRateLimits_scope_key_pk", + "columns": [ + "scope", + "key" + ] + } + }, + "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 + }, + "code_hash": { + "name": "code_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.whlg": { + "name": "whlg", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.aspect_type": { + "name": "aspect_type", + "schema": "public", + "values": [ + "material", + "condition", + "type", + "area", + "configuration", + "presence", + "risk", + "severity", + "location", + "finish", + "insulation", + "pointing", + "spalling", + "lintels", + "cladding", + "category", + "quantity", + "adequacy", + "rating", + "strategy", + "extent", + "distribution", + "structure", + "covering", + "fire_rating", + "external_decoration", + "work_required", + "age_band", + "construction_type", + "classification", + "system" + ] + }, + "public.element_type": { + "name": "element_type", + "schema": "public", + "values": [ + "property", + "property_construction_type", + "property_classification", + "property_age_band", + "storey_count", + "floor_level", + "floor_level_front_door", + "accessible_housing_register", + "asbestos", + "quality_standard", + "ccu", + "passenger_lift", + "stairlift", + "disabled_hoist_tracking", + "disabled_facilities", + "steps_to_front_door", + "roof", + "pitched_roof_covering", + "flat_roof_covering", + "rainwater_goods", + "loft_insulation", + "porch_canopy", + "chimney", + "fascia", + "soffit", + "fascia_soffit_bargeboards", + "gutters", + "store_roof", + "garage_roof", + "garage_and_store_roof", + "external_wall", + "external_noise_insulation", + "primary_wall", + "secondary_wall", + "downpipes", + "external_decoration", + "cladding", + "spandrel_panels", + "garage_walls", + "party_wall_fire_break", + "external_brickwork_pointing", + "internal_downpipes_external_area", + "external_windows", + "communal_windows", + "secondary_glazing", + "store_windows", + "garage_windows", + "garage_and_store_windows", + "external_door", + "front_door", + "rear_door", + "store_door", + "garage_door", + "garage_and_store_door", + "communal_entrance_door", + "main_door", + "block_entrance_door", + "lintel", + "patio_french_door", + "door_entry_handset", + "paths_and_hardstandings", + "parking_areas", + "boundary_walls", + "front_fencing", + "rear_fencing", + "side_fencing", + "rear_gate", + "front_gate", + "gates", + "retaining_walls", + "private_balcony", + "balcony_balustrade", + "outbuildings", + "garage_structure", + "paving", + "roads", + "soil_and_vent", + "solar_thermals", + "drop_kerb", + "outbuilding_overhaul", + "external_structural_defects", + "access_ramp", + "kitchen", + "kitchen_space_layout", + "tenant_installed_kitchen", + "kitchen_extractor_fan", + "bathroom", + "secondary_bathroom", + "secondary_toilet", + "bathroom_extractor_fan", + "additional_wc_or_whb", + "bathroom_remaining_life_source", + "kitchen_remaining_life_source", + "central_heating", + "heating_boiler", + "heating_distribution", + "secondary_heating", + "hot_water_system", + "cold_water_storage", + "heating_system", + "boiler_fuel", + "water_heating", + "programmable_heating", + "community_heating", + "gas_available", + "heat_recovery_units", + "heating_improvements", + "electrical_wiring", + "consumer_unit", + "smoke_detection", + "heat_detection", + "carbon_monoxide_detection", + "fire_door_rating", + "fire_risk_assessment", + "internal_wiring", + "electrics", + "communal_heating", + "communal_boiler", + "communal_electrics", + "communal_fire_alarm", + "communal_emergency_lighting", + "communal_door_entry", + "communal_cctv", + "communal_bin_store", + "communal_bin_store_doors", + "communal_bin_store_walls", + "communal_bin_store_roof", + "communal_refuse_chute", + "communal_floor_covering", + "communal_kitchen", + "communal_bathroom", + "communal_toilets", + "communal_gates", + "communal_lift", + "communal_passenger_lift", + "communal_balcony_walkway", + "communal_entrance", + "communal_internal_decorations", + "communal_internal_floor", + "communal_walkways", + "communal_external_doors", + "communal_stairs", + "communal_aerial", + "communal_aov", + "communal_internal_doors", + "communal_lateral_mains", + "communal_lighting", + "communal_lighting_conductor", + "communal_store_roof", + "communal_store_walls", + "communal_store_doors", + "communal_warden_call_system", + "communal_bms", + "communal_booster_pump", + "communal_dry_riser", + "communal_wet_riser", + "communal_cold_water_storage", + "communal_sprinkler", + "communal_plug_sockets", + "communal_circulation_space", + "ffhh_damp", + "ffhh_hold_and_cold_water", + "ffhh_drainage_lavatories", + "ffhh_neglected", + "ffhh_natural_light", + "ffhh_ventilation", + "ffhh_food_prep_and_washup", + "ffhh_unsafe_layout", + "ffhh_unstable_building", + "hhsrs_damp_and_mould", + "hhsrs_excess_cold", + "hhsrs_excess_heat", + "hhsrs_asbestos_and_mmf", + "hhsrs_biocides", + "hhsrs_carbon_monoxide", + "hhsrs_lead", + "hhsrs_radiation", + "hhsrs_uncombusted_fuel_gas", + "hhsrs_volatile_organic_compounds", + "hhsrs_crowding_and_space", + "hhsrs_entry_by_intruders", + "hhsrs_lighting", + "hhsrs_noise", + "hhsrs_domestic_hygiene_pests_refuse", + "hhsrs_food_safety", + "hhsrs_personal_hygiene_sanitation", + "hhsrs_water_supply", + "hhsrs_falls_associated_with_baths", + "hhsrs_falls_on_level_surfaces", + "hhsrs_falls_on_stairs", + "hhsrs_falls_between_levels", + "hhsrs_electrical_hazards", + "hhsrs_fire", + "hhsrs_flames_hot_surfaces", + "hhsrs_collision_and_entrapment", + "hhsrs_collision_hazards_low_headroom", + "hhsrs_explosions", + "hhsrs_ergonomics", + "hhsrs_structural_collapse", + "hhsrs_amenities" + ] + }, + "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.inspection_archetype_2": { + "name": "inspection_archetype_2", + "schema": "public", + "values": [ + "detached", + "mid-terrace", + "enclosed mid-terrace", + "end-terrace", + "enclosed end-terrace", + "semi-detached" + ] + }, + "public.inspection_archetype": { + "name": "inspection_archetype", + "schema": "public", + "values": [ + "Bungalow", + "Flat", + "Maisonette", + "House", + "non-domestic" + ] + }, + "public.inspection_borescoped": { + "name": "inspection_borescoped", + "schema": "public", + "values": [ + "yes", + "no", + "refused" + ] + }, + "public.inspections_access_issues": { + "name": "inspections_access_issues", + "schema": "public", + "values": [ + "see notes", + "damp issues", + "foliage on walls", + "bushes against wall", + "trees around/anove property", + "high rise block flats/maisonettes", + "conservatory", + "lean-to", + "garage", + "extension", + "decking", + "shed against wall" + ] + }, + "public.inspections_cladding": { + "name": "inspections_cladding", + "schema": "public", + "values": [ + "none", + "cladded with “sufficient space to fill the wall”", + "cladded with “insufficient space to fill the wall”" + ] + }, + "public.inspections_insulation_material": { + "name": "inspections_insulation_material", + "schema": "public", + "values": [ + "empty 50-90", + "empty 100+", + "empty 30-40", + "empty less than 30", + "loose fibre/wool", + "eps/celo/king", + "fibre batts - with cavity", + "fibre batts - no cavity", + "loose bead", + "glued bead", + "formaldehyde", + "bubble wrap", + "poly chunks" + ] + }, + "public.inspections_rendered": { + "name": "inspections_rendered", + "schema": "public", + "values": [ + "no render", + "rendered with “insufficient” space between dpc and render", + "rendered with “sufficient” space between dpc and render" + ] + }, + "public.inspections_roof_orientation": { + "name": "inspections_roof_orientation", + "schema": "public", + "values": [ + "north", + "east", + "south", + "west", + "north-east", + "north-west", + "south-east", + "south-west", + "n/s split", + "e/w split", + "ne/sw split", + "nw/se split", + "flat roof", + "no roof", + "roof too small", + "already has solar pv" + ] + }, + "public.inspections_tile_hung": { + "name": "inspections_tile_hung", + "schema": "public", + "values": [ + "yes", + "no", + "first floor flats are tile hung" + ] + }, + "public.inspections_wall_construction": { + "name": "inspections_wall_construction", + "schema": "public", + "values": [ + "cavity", + "solid", + "system built", + "timber framed", + "steel framed", + "re-walled cavity", + "mansard pre-fab", + "mansard ewi", + "mansard re-walled" + ] + }, + "public.inspections_wall_insulation": { + "name": "inspections_wall_insulation", + "schema": "public", + "values": [ + "empty cavity", + "filled at build", + "partial", + "retro drilled", + "ewi", + "iwi", + "solid non-cavity", + "system built", + "timber framed", + "steel framed" + ] + }, + "public.built_form_type": { + "name": "built_form_type", + "schema": "public", + "values": [ + "Detached", + "Semi-Detached", + "Mid-Terrace", + "End-Terrace", + "Enclosed Mid-Terrace", + "Enclosed End-Terrace", + "Not Recorded", + "Unknown" + ] + }, + "public.construction_age_band": { + "name": "construction_age_band", + "schema": "public", + "values": [ + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "Unknown" + ] + }, + "public.glazing": { + "name": "glazing", + "schema": "public", + "values": [ + "Single glazing", + "Double glazing, 2002 or later", + "Double glazing, pre-2002", + "Triple glazing, pre-2002", + "Triple glazing, 2002 or later", + "Mixed glazing", + "Secondary glazing", + "Unknown" + ] + }, + "public.main_fuel": { + "name": "main_fuel", + "schema": "public", + "values": [ + "mains gas", + "mains gas (community)", + "electricity", + "electricity (community)", + "LPG (bulk)", + "bottled LPG", + "LPG special condition", + "oil", + "house coal", + "smokeless coal", + "dual fuel (mineral and wood)", + "biomass (community)", + "wood logs", + "Unknown" + ] + }, + "public.main_heating_system": { + "name": "main_heating_system", + "schema": "public", + "values": [ + "Gas boiler, combi", + "Gas boiler, regular", + "Gas CPSU", + "Electric storage heaters, old", + "Electric storage heaters, slimline", + "Electric storage heaters, convector", + "Electric storage heaters, fan", + "Direct-acting electric", + "Electric room heaters", + "Solid fuel room heater, closed", + "Air source heat pump", + "Community heating, boilers", + "Community heating, CHP and boilers", + "Oil room heater, 2000 or later", + "Gas room heater, condensing fire", + "Gas room heater, decorative fuel-effect", + "Gas room heater, flush live-effect", + "Gas room heater, open flue 1980 or later", + "Gas room heater, open flue pre-1980", + "Electric storage heaters, high heat retention", + "Solid fuel room heater, open fire", + "Solid fuel room heater, open fire with back boiler", + "Solid fuel room heater, closed with boiler", + "Electric boiler", + "Electric CPSU", + "Electric underfloor, in concrete slab (off-peak)", + "Electric underfloor, integrated storage and direct-acting", + "Electric underfloor, in screed above insulation", + "Unknown" + ] + }, + "public.override_source": { + "name": "override_source", + "schema": "public", + "values": [ + "classifier", + "user", + "os_places" + ] + }, + "public.property_type": { + "name": "property_type", + "schema": "public", + "values": [ + "House", + "Bungalow", + "Flat", + "Maisonette", + "Park home", + "Unknown" + ] + }, + "public.roof_type": { + "name": "roof_type", + "schema": "public", + "values": [ + "Flat, insulated", + "Flat, insulated (assumed)", + "Flat, limited insulation", + "Flat, limited insulation (assumed)", + "Flat, no insulation", + "Flat, no insulation (assumed)", + "Flat, 12 mm insulation", + "Flat, 25 mm insulation", + "Flat, 50 mm insulation", + "Flat, 75 mm insulation", + "Flat, 100 mm insulation", + "Flat, 125 mm insulation", + "Flat, 150 mm insulation", + "Flat, 175 mm insulation", + "Flat, 200 mm insulation", + "Flat, 225 mm insulation", + "Flat, 250 mm insulation", + "Flat, 270 mm insulation", + "Flat, 300 mm insulation", + "Flat, 350 mm insulation", + "Flat, 400 mm insulation", + "Flat, 400+ mm insulation", + "Pitched, insulated", + "Pitched, insulated (assumed)", + "Pitched, insulated at rafters", + "Pitched, limited insulation", + "Pitched, limited insulation (assumed)", + "Pitched, no insulation", + "Pitched, no insulation (assumed)", + "Pitched, Unknown loft insulation", + "Pitched, 0 mm loft insulation", + "Pitched, 12 mm loft insulation", + "Pitched, 25 mm loft insulation", + "Pitched, 50 mm loft insulation", + "Pitched, 75 mm loft insulation", + "Pitched, 100 mm loft insulation", + "Pitched, 125 mm loft insulation", + "Pitched, 150 mm loft insulation", + "Pitched, 175 mm loft insulation", + "Pitched, 200 mm loft insulation", + "Pitched, 225 mm loft insulation", + "Pitched, 250 mm loft insulation", + "Pitched, 270 mm loft insulation", + "Pitched, 300 mm loft insulation", + "Pitched, 350 mm loft insulation", + "Pitched, 400 mm loft insulation", + "Pitched, 400+ mm loft insulation", + "Roof room(s), insulated", + "Roof room(s), insulated (assumed)", + "Roof room(s), limited insulation", + "Roof room(s), limited insulation (assumed)", + "Roof room(s), no insulation", + "Roof room(s), no insulation (assumed)", + "Roof room(s), ceiling insulated", + "Roof room(s), thatched", + "Roof room(s), thatched with additional insulation", + "Thatched", + "Thatched, with additional insulation", + "(another dwelling above)", + "(same dwelling above)", + "(other premises above)", + "(another premises above)", + "Another Premises Above", + "Unknown" + ] + }, + "public.wall_type": { + "name": "wall_type", + "schema": "public", + "values": [ + "Cavity wall, filled cavity", + "Cavity wall, as built, insulated (assumed)", + "Cavity wall, as built, no insulation (assumed)", + "Cavity wall, as built, partial insulation (assumed)", + "Cavity wall, with internal insulation", + "Cavity wall, with external insulation", + "Cavity wall, filled cavity and internal insulation", + "Cavity wall, filled cavity and external insulation", + "Solid brick, as built, no insulation (assumed)", + "Solid brick, as built, insulated (assumed)", + "Solid brick, as built, partial insulation (assumed)", + "Solid brick, with internal insulation", + "Solid brick, with external insulation", + "Timber frame, as built, no insulation (assumed)", + "Timber frame, as built, insulated (assumed)", + "Timber frame, as built, partial insulation (assumed)", + "Timber frame, with additional insulation", + "Sandstone, as built, no insulation (assumed)", + "Sandstone, as built, insulated (assumed)", + "Sandstone, as built, partial insulation (assumed)", + "Sandstone, with internal insulation", + "Sandstone, with external insulation", + "Granite or whin, as built, no insulation (assumed)", + "Granite or whin, as built, insulated (assumed)", + "Granite or whin, as built, partial insulation (assumed)", + "Granite or whin, with internal insulation", + "Granite or whin, with external insulation", + "System built, as built, no insulation (assumed)", + "System built, as built, insulated (assumed)", + "System built, as built, partial insulation (assumed)", + "System built, with internal insulation", + "System built, with external insulation", + "Park home wall, as built", + "Park home wall, with internal insulation", + "Park home wall, with external insulation", + "Cob, as built", + "Cob, with internal insulation", + "Cob, with external insulation", + "Curtain wall", + "Curtain Wall, as built, no insulation (assumed)", + "Curtain Wall, as built, insulated (assumed)", + "Curtain Wall, filled cavity", + "Curtain Wall, with internal insulation", + "Basement wall", + "Basement wall, as built", + "Unknown" + ] + }, + "public.water_heating": { + "name": "water_heating", + "schema": "public", + "values": [ + "From main system, mains gas", + "From main system, electricity", + "From main system, oil", + "From main system, LPG (bulk)", + "From main system, bottled LPG", + "From main system, house coal", + "Electric immersion, electricity", + "Gas boiler/circulator, mains gas", + "From main system, wood logs", + "From main system, biomass (community)", + "From main system, dual fuel (mineral and wood)", + "From main system, biodiesel (community)", + "Unknown" + ] + }, + "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", + "secondary_glazing", + "double_glazing", + "trickle_vent", + "door_undercut", + "solar_pv", + "solar_battery", + "scaffolding", + "high_heat_retention_storage_heaters", + "air_source_heat_pump", + "boiler_upgrade", + "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.portfolio_capability": { + "name": "portfolio_capability", + "schema": "public", + "values": [ + "approver", + "contractor" + ] + }, + "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.override_component": { + "name": "override_component", + "schema": "public", + "values": [ + "wall_type", + "roof_type", + "property_type", + "built_form_type", + "main_fuel", + "glazing", + "construction_age_band", + "water_heating", + "main_heating_system" + ] + }, + "public.energy_element_type": { + "name": "energy_element_type", + "schema": "public", + "values": [ + "roof", + "wall", + "floor", + "main_heating", + "window", + "lighting", + "hot_water", + "secondary_heating", + "main_heating_controls" + ] + }, + "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.rebaseline_reason": { + "name": "rebaseline_reason", + "schema": "public", + "values": [ + "none", + "pre_sap10", + "physical_state_changed", + "both" + ] + }, + "public.housing_type": { + "name": "housing_type", + "schema": "public", + "values": [ + "Private", + "Social" + ] + }, + "public.measure_type": { + "name": "measure_type", + "schema": "public", + "values": [ + "air_source_heat_pump", + "boiler_upgrade", + "high_heat_retention_storage_heaters", + "secondary_heating", + "roomstat_programmer_trvs", + "time_temperature_zone_control", + "cylinder_thermostat", + "cavity_wall_insulation", + "extension_cavity_wall_insulation", + "external_wall_insulation", + "internal_wall_insulation", + "loft_insulation", + "flat_roof_insulation", + "room_roof_insulation", + "solid_floor_insulation", + "suspended_floor_insulation", + "double_glazing", + "secondary_glazing", + "draught_proofing", + "mechanical_ventilation", + "low_energy_lighting", + "solar_pv", + "hot_water_tank_insulation", + "sealing_open_fireplace" + ] + }, + "public.plan_type": { + "name": "plan_type", + "schema": "public", + "values": [ + "solar_eco4", + "solar_hhrsh_eco4", + "empty_cavity_eco", + "partial_cavity_eco", + "extraction_eco" + ] + }, + "public.unit_quantity": { + "name": "unit_quantity", + "schema": "public", + "values": [ + "m2", + "part", + "kwp" + ] + }, + "public.scenario_type": { + "name": "scenario_type", + "schema": "public", + "values": [ + "unit", + "building" + ] + }, + "public.source": { + "name": "source", + "schema": "public", + "values": [ + "portfolio_id", + "hubspot_deal_id", + "property_id" + ] + }, + "public.file_source": { + "name": "file_source", + "schema": "public", + "values": [ + "pas hub", + "sharepoint", + "hubspot", + "ecmk", + "contractor", + "magic_plan", + "coordination_hub", + "audit_generator", + "projects" + ] + }, + "public.file_type": { + "name": "file_type", + "schema": "public", + "values": [ + "photo_pack", + "site_note", + "rd_sap_site_note", + "pas_2023_ventilation", + "pas_2023_condition", + "pas_significance", + "par_photo_pack", + "pas_2023_property", + "pas_2023_occupancy", + "ecmk_site_note", + "ecmk_rd_sap_site_note", + "ecmk_survey_xml", + "pre_photo", + "mid_photo", + "post_photo", + "loft_hatch_photo", + "dmev_photos", + "door_undercut_photos", + "trickle_vent_photos", + "pre_installation_building_inspection", + "point_of_work_risk_assessment", + "claim_of_compliance", + "mcs_compliance_certificate", + "certificate_of_conformity", + "minor_works_electrical_certificate", + "trustmark_licence_numbers", + "operative_competency", + "ventilation_assessment_checklist", + "anemometer_readings", + "commissioning_records", + "part_f_ventilation_document", + "handover_pack", + "insurance_guarantee", + "workmanship_warranty", + "g98_notification", + "installer_qualifications", + "installer_feedback", + "contractor_other", + "magic_plan_json", + "improvement_option_evaluation", + "medium_term_improvement_plan", + "retrofit_design_doc", + "ventilation_audit", + "other" + ] + }, + "public.user_defined_deal_measure_source": { + "name": "user_defined_deal_measure_source", + "schema": "public", + "values": [ + "instructed", + "pibi_ordered" + ] + }, + "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/0277_snapshot.json b/src/app/db/migrations/meta/0277_snapshot.json new file mode 100644 index 00000000..1a3e7851 --- /dev/null +++ b/src/app/db/migrations/meta/0277_snapshot.json @@ -0,0 +1,13472 @@ +{ + "id": "43985c13-e221-4ced-b131-844eefb2330b", + "prevId": "e5296a66-470c-46da-8a10-8149852ef94c", + "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()" + }, + "last_updated_at": { + "name": "last_updated_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.deal_measure_approval_events": { + "name": "deal_measure_approval_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "acted_by": { + "name": "acted_by", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "acted_at": { + "name": "acted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_deal_measure_events_deal_id": { + "name": "idx_deal_measure_events_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_deal_measure_events_acted_at": { + "name": "idx_deal_measure_events_acted_at", + "columns": [ + { + "expression": "acted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deal_measure_approval_events_acted_by_user_id_fk": { + "name": "deal_measure_approval_events_acted_by_user_id_fk", + "tableFrom": "deal_measure_approval_events", + "tableTo": "user", + "columnsFrom": [ + "acted_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deal_measure_approvals": { + "name": "deal_measure_approvals", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_approved": { + "name": "is_approved", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "approved_by": { + "name": "approved_by", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "approved_at": { + "name": "approved_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_deal_measure_approvals_deal_id": { + "name": "idx_deal_measure_approvals_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deal_measure_approvals_approved_by_user_id_fk": { + "name": "deal_measure_approvals_approved_by_user_id_fk", + "tableFrom": "deal_measure_approvals", + "tableTo": "user", + "columnsFrom": [ + "approved_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "uq_deal_measure": { + "name": "uq_deal_measure", + "nullsNotDistinct": false, + "columns": [ + "hubspot_deal_id", + "measure_name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bulk_address_uploads": { + "name": "bulk_address_uploads", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "s3_bucket": { + "name": "s3_bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "s3_key": { + "name": "s3_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "filename": { + "name": "filename", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'ready_for_processing'" + }, + "source_headers": { + "name": "source_headers", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "column_mapping": { + "name": "column_mapping", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "multi_entry_summary": { + "name": "multi_entry_summary", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "multi_entry_ordering": { + "name": "multi_entry_ordering", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "verify_ack": { + "name": "verify_ack", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "task_id": { + "name": "task_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "combined_output_s3_uri": { + "name": "combined_output_s3_uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bulk_upload_uprn_corrections": { + "name": "bulk_upload_uprn_corrections", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "upload_id": { + "name": "upload_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "source_row_id": { + "name": "source_row_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address": { + "name": "address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "marked_no_uprn": { + "name": "marked_no_uprn", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "bulk_upload_uprn_corrections_upload_id_bulk_address_uploads_id_fk": { + "name": "bulk_upload_uprn_corrections_upload_id_bulk_address_uploads_id_fk", + "tableFrom": "bulk_upload_uprn_corrections", + "tableTo": "bulk_address_uploads", + "columnsFrom": [ + "upload_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "bulk_upload_uprn_corrections_upload_row_unique": { + "name": "bulk_upload_uprn_corrections_upload_row_unique", + "nullsNotDistinct": false, + "columns": [ + "upload_id", + "source_row_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.aspect_condition": { + "name": "aspect_condition", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "element_id": { + "name": "element_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "aspect_type": { + "name": "aspect_type", + "type": "aspect_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "aspect_instance": { + "name": "aspect_instance", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "quantity": { + "name": "quantity", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "install_date": { + "name": "install_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "renewal_year": { + "name": "renewal_year", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "comments": { + "name": "comments", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "aspect_condition_element_id_element_id_fk": { + "name": "aspect_condition_element_id_element_id_fk", + "tableFrom": "aspect_condition", + "tableTo": "element", + "columnsFrom": [ + "element_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.element": { + "name": "element", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "survey_id": { + "name": "survey_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "element_type": { + "name": "element_type", + "type": "element_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "element_instance": { + "name": "element_instance", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "element_survey_id_property_condition_survey_id_fk": { + "name": "element_survey_id_property_condition_survey_id_fk", + "tableFrom": "element", + "tableTo": "property_condition_survey", + "columnsFrom": [ + "survey_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_condition_survey": { + "name": "property_condition_survey", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "date": { + "name": "date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hubspot_company_data": { + "name": "hubspot_company_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "company_name": { + "name": "company_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "group_id": { + "name": "group_id", + "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": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hubspot_deal_data": { + "name": "hubspot_deal_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "deal_id": { + "name": "deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dealname": { + "name": "dealname", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dealstage": { + "name": "dealstage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "company_id": { + "name": "company_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "project_code": { + "name": "project_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "landlord_property_id": { + "name": "landlord_property_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "listing_id": { + "name": "listing_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uprn": { + "name": "uprn", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "outcome": { + "name": "outcome", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "outcome_notes": { + "name": "outcome_notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "major_condition_issue_description": { + "name": "major_condition_issue_description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "major_condition_issue_photos": { + "name": "major_condition_issue_photos", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "major_condition_issue_evidence_s3_url": { + "name": "major_condition_issue_evidence_s3_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "coordination_status": { + "name": "coordination_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "design_status": { + "name": "design_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "booking_status": { + "name": "booking_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pashub_link": { + "name": "pashub_link", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sharepoint_link": { + "name": "sharepoint_link", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dampmould_growth": { + "name": "dampmould_growth", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pre_sap": { + "name": "pre_sap", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "coordinator": { + "name": "coordinator", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mtp_completion_date": { + "name": "mtp_completion_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "mtp_re_model_completion_date": { + "name": "mtp_re_model_completion_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "ioe_v3_completion_date": { + "name": "ioe_v3_completion_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "proposed_measures": { + "name": "proposed_measures", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "approved_package": { + "name": "approved_package", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "designer": { + "name": "designer", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "design_type": { + "name": "design_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "design_completion_date": { + "name": "design_completion_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "actual_measures_installed": { + "name": "actual_measures_installed", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "installer": { + "name": "installer", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "installer_handover": { + "name": "installer_handover", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lodgement_status": { + "name": "lodgement_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "measures_lodgement_date": { + "name": "measures_lodgement_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "lodgement_date": { + "name": "lodgement_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "expected_commencement_date": { + "name": "expected_commencement_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "coordination_comments": { + "name": "coordination_comments", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "surveyor": { + "name": "surveyor", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "damp_mould_and_repairs_comments": { + "name": "damp_mould_and_repairs_comments", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "batch": { + "name": "batch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "batch_description": { + "name": "batch_description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "block_reference": { + "name": "block_reference", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "nonfunded_measures": { + "name": "nonfunded_measures", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_prn": { + "name": "epc_prn", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "potential_post_sap_score_dropdown": { + "name": "potential_post_sap_score_dropdown", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ei_score": { + "name": "ei_score", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ei_score__potential_": { + "name": "ei_score__potential_", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_sap_score": { + "name": "epc_sap_score", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_sap_score__potential_": { + "name": "epc_sap_score__potential_", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmed_survey_date": { + "name": "confirmed_survey_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "confirmed_survey_time": { + "name": "confirmed_survey_time", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "surveyed_date": { + "name": "surveyed_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "survey_type": { + "name": "survey_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "measures_for_pibi_ordered": { + "name": "measures_for_pibi_ordered", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pibi_order_date": { + "name": "pibi_order_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "pibi_completed_date": { + "name": "pibi_completed_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "property_halted_date": { + "name": "property_halted_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "property_halted_reason": { + "name": "property_halted_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "technical_approved_measures_for_install": { + "name": "technical_approved_measures_for_install", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sent_to_installer_for_pricing": { + "name": "sent_to_installer_for_pricing", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "domna_survey_required": { + "name": "domna_survey_required", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "domna_survey_type": { + "name": "domna_survey_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "domna_survey_date": { + "name": "domna_survey_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "date_booking_made": { + "name": "date_booking_made", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "last_contact_date": { + "name": "last_contact_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "last_outbound_call": { + "name": "last_outbound_call", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "last_outbound_email": { + "name": "last_outbound_email", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "last_submission_date": { + "name": "last_submission_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "number_of_attempts": { + "name": "number_of_attempts", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "client_booking_reference": { + "name": "client_booking_reference", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "third_party_surveyor_identifier": { + "name": "third_party_surveyor_identifier", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "design_constraints": { + "name": "design_constraints", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "planning_comments": { + "name": "planning_comments", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "planning_status": { + "name": "planning_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "planning_suggested_approach": { + "name": "planning_suggested_approach", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "planning_authority": { + "name": "planning_authority", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "designated_area": { + "name": "designated_area", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "article_4_pd_rights": { + "name": "article_4_pd_rights", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "listed_building": { + "name": "listed_building", + "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": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hubspot_projects_data": { + "name": "hubspot_projects_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "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": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "hubspot_projects_data_project_id_unique": { + "name": "hubspot_projects_data_project_id_unique", + "nullsNotDistinct": false, + "columns": [ + "project_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hubspot_users": { + "name": "hubspot_users", + "schema": "", + "columns": { + "hubspot_owner_id": { + "name": "hubspot_owner_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "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.epc_store": { + "name": "epc_store", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "epc_api_created_at": { + "name": "epc_api_created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "epc_api": { + "name": "epc_api", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "epc_page_created_at": { + "name": "epc_page_created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "epc_page": { + "name": "epc_page", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_page_rrn": { + "name": "epc_page_rrn", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "uq_epc_store_uprn": { + "name": "uq_epc_store_uprn", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.files_from_surveyor": { + "name": "files_from_surveyor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "s3_json_url": { + "name": "s3_json_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "files_from_surveyor_portfolio_id_portfolio_id_fk": { + "name": "files_from_surveyor_portfolio_id_portfolio_id_fk", + "tableFrom": "files_from_surveyor", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "files_from_surveyor_property_id_property_id_fk": { + "name": "files_from_surveyor_property_id_property_id_fk", + "tableFrom": "files_from_surveyor", + "tableTo": "property", + "columnsFrom": [ + "property_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.inspections": { + "name": "inspections", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "archetype": { + "name": "archetype", + "type": "inspection_archetype", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "archetype_2": { + "name": "archetype_2", + "type": "inspection_archetype_2", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "wall_construction": { + "name": "wall_construction", + "type": "inspections_wall_construction", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "insulation": { + "name": "insulation", + "type": "inspections_wall_insulation", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "insulation_material": { + "name": "insulation_material", + "type": "inspections_insulation_material", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "borescoped": { + "name": "borescoped", + "type": "inspection_borescoped", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "roof_orientation": { + "name": "roof_orientation", + "type": "inspections_roof_orientation", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "tile_hung": { + "name": "tile_hung", + "type": "inspections_tile_hung", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "rendered": { + "name": "rendered", + "type": "inspections_rendered", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "cladding": { + "name": "cladding", + "type": "inspections_cladding", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "access_issues": { + "name": "access_issues", + "type": "inspections_access_issues", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "surveyor_name": { + "name": "surveyor_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "inspections_property_id_property_id_fk": { + "name": "inspections_property_id_property_id_fk", + "tableFrom": "inspections", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_built_form_type_overrides": { + "name": "landlord_built_form_type_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "built_form_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_built_form_type_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_built_form_type_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_built_form_type_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_built_form_type_overrides_portfolio_description_unique": { + "name": "landlord_built_form_type_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_construction_age_band_overrides": { + "name": "landlord_construction_age_band_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "construction_age_band", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_construction_age_band_overrides_portfolio_fk": { + "name": "landlord_construction_age_band_overrides_portfolio_fk", + "tableFrom": "landlord_construction_age_band_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_construction_age_band_portfolio_description_unique": { + "name": "landlord_construction_age_band_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_glazing_overrides": { + "name": "landlord_glazing_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "glazing", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_glazing_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_glazing_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_glazing_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_glazing_overrides_portfolio_description_unique": { + "name": "landlord_glazing_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_main_fuel_overrides": { + "name": "landlord_main_fuel_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "main_fuel", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_main_fuel_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_main_fuel_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_main_fuel_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_main_fuel_overrides_portfolio_description_unique": { + "name": "landlord_main_fuel_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_main_heating_system_overrides": { + "name": "landlord_main_heating_system_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "main_heating_system", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_main_heating_system_overrides_portfolio_fk": { + "name": "landlord_main_heating_system_overrides_portfolio_fk", + "tableFrom": "landlord_main_heating_system_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_main_heating_system_portfolio_description_unique": { + "name": "landlord_main_heating_system_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_property_type_overrides": { + "name": "landlord_property_type_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "property_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_property_type_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_property_type_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_property_type_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_property_type_overrides_portfolio_description_unique": { + "name": "landlord_property_type_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_roof_type_overrides": { + "name": "landlord_roof_type_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "roof_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_roof_type_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_roof_type_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_roof_type_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_roof_type_overrides_portfolio_description_unique": { + "name": "landlord_roof_type_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_wall_type_overrides": { + "name": "landlord_wall_type_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "wall_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_wall_type_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_wall_type_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_wall_type_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_wall_type_overrides_portfolio_description_unique": { + "name": "landlord_wall_type_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_water_heating_overrides": { + "name": "landlord_water_heating_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "water_heating", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_water_heating_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_water_heating_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_water_heating_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_water_heating_overrides_portfolio_description_unique": { + "name": "landlord_water_heating_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_door_ventilation": { + "name": "magic_plan_door_ventilation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_door_id": { + "name": "magic_plan_door_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "undercut_mm": { + "name": "undercut_mm", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_door_ventilation_magic_plan_door_id_magic_plan_door_id_fk": { + "name": "magic_plan_door_ventilation_magic_plan_door_id_magic_plan_door_id_fk", + "tableFrom": "magic_plan_door_ventilation", + "tableTo": "magic_plan_door", + "columnsFrom": [ + "magic_plan_door_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "magic_plan_door_ventilation_magic_plan_door_id_unique": { + "name": "magic_plan_door_ventilation_magic_plan_door_id_unique", + "nullsNotDistinct": false, + "columns": [ + "magic_plan_door_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_door": { + "name": "magic_plan_door", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_room_id": { + "name": "magic_plan_room_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "width_mm": { + "name": "width_mm", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "height_mm": { + "name": "height_mm", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_door_magic_plan_room_id_magic_plan_room_id_fk": { + "name": "magic_plan_door_magic_plan_room_id_magic_plan_room_id_fk", + "tableFrom": "magic_plan_door", + "tableTo": "magic_plan_room", + "columnsFrom": [ + "magic_plan_room_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_floor": { + "name": "magic_plan_floor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_plan_id": { + "name": "magic_plan_plan_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "level": { + "name": "level", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_floor_magic_plan_plan_id_magic_plan_plan_id_fk": { + "name": "magic_plan_floor_magic_plan_plan_id_magic_plan_plan_id_fk", + "tableFrom": "magic_plan_floor", + "tableTo": "magic_plan_plan", + "columnsFrom": [ + "magic_plan_plan_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_plan": { + "name": "magic_plan_plan", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address": { + "name": "address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "magic_plan_uid": { + "name": "magic_plan_uid", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uploaded_file_id": { + "name": "uploaded_file_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_plan_uploaded_file_id_uploaded_files_id_fk": { + "name": "magic_plan_plan_uploaded_file_id_uploaded_files_id_fk", + "tableFrom": "magic_plan_plan", + "tableTo": "uploaded_files", + "columnsFrom": [ + "uploaded_file_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "magic_plan_plan_magic_plan_uid_unique": { + "name": "magic_plan_plan_magic_plan_uid_unique", + "nullsNotDistinct": false, + "columns": [ + "magic_plan_uid" + ] + }, + "magic_plan_plan_uploaded_file_id_unique": { + "name": "magic_plan_plan_uploaded_file_id_unique", + "nullsNotDistinct": false, + "columns": [ + "uploaded_file_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_room": { + "name": "magic_plan_room", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_floor_id": { + "name": "magic_plan_floor_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "width_m": { + "name": "width_m", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "length_m": { + "name": "length_m", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "area_m2": { + "name": "area_m2", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_room_magic_plan_floor_id_magic_plan_floor_id_fk": { + "name": "magic_plan_room_magic_plan_floor_id_magic_plan_floor_id_fk", + "tableFrom": "magic_plan_room", + "tableTo": "magic_plan_floor", + "columnsFrom": [ + "magic_plan_floor_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_window_ventilation": { + "name": "magic_plan_window_ventilation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_window_id": { + "name": "magic_plan_window_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "opening_type": { + "name": "opening_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "num_openings": { + "name": "num_openings", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "pct_openable": { + "name": "pct_openable", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "trickle_vent_area_mm2": { + "name": "trickle_vent_area_mm2", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "num_trickle_vents": { + "name": "num_trickle_vents", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_window_ventilation_magic_plan_window_id_magic_plan_window_id_fk": { + "name": "magic_plan_window_ventilation_magic_plan_window_id_magic_plan_window_id_fk", + "tableFrom": "magic_plan_window_ventilation", + "tableTo": "magic_plan_window", + "columnsFrom": [ + "magic_plan_window_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "magic_plan_window_ventilation_magic_plan_window_id_unique": { + "name": "magic_plan_window_ventilation_magic_plan_window_id_unique", + "nullsNotDistinct": false, + "columns": [ + "magic_plan_window_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_window": { + "name": "magic_plan_window", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_room_id": { + "name": "magic_plan_room_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "width_m": { + "name": "width_m", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "height_m": { + "name": "height_m", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "area_m2": { + "name": "area_m2", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_window_magic_plan_room_id_magic_plan_room_id_fk": { + "name": "magic_plan_window_magic_plan_room_id_magic_plan_room_id_fk", + "tableFrom": "magic_plan_window", + "tableTo": "magic_plan_room", + "columnsFrom": [ + "magic_plan_room_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": { + "idx_material_active": { + "name": "idx_material_active", + "columns": [ + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"material\".\"is_active\"", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organisation": { + "name": "organisation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "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()" + }, + "hubspot_company_id": { + "name": "hubspot_company_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pibi_requests": { + "name": "pibi_requests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "ordered_at": { + "name": "ordered_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "pushed_at": { + "name": "pushed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_pibi_requests_deal_id": { + "name": "idx_pibi_requests_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_pibi_requests_portfolio_id": { + "name": "idx_pibi_requests_portfolio_id", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pibi_requests_portfolio_id_portfolio_id_fk": { + "name": "pibi_requests_portfolio_id_portfolio_id_fk", + "tableFrom": "pibi_requests", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "pibi_requests_created_by_user_id_user_id_fk": { + "name": "pibi_requests_created_by_user_id_user_id_fk", + "tableFrom": "pibi_requests", + "tableTo": "user", + "columnsFrom": [ + "created_by_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.portfolio_organisation": { + "name": "portfolio_organisation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "organisation_id": { + "name": "organisation_id", + "type": "uuid", + "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": { + "portfolio_organisation_portfolio_id_portfolio_id_fk": { + "name": "portfolio_organisation_portfolio_id_portfolio_id_fk", + "tableFrom": "portfolio_organisation", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "portfolio_organisation_organisation_id_organisation_id_fk": { + "name": "portfolio_organisation_organisation_id_organisation_id_fk", + "tableFrom": "portfolio_organisation", + "tableTo": "organisation", + "columnsFrom": [ + "organisation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "portfolio_organisation_portfolio_id_organisation_id_unique": { + "name": "portfolio_organisation_portfolio_id_organisation_id_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "organisation_id" + ] + } + }, + "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.portfolio_capabilities": { + "name": "portfolio_capabilities", + "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 + }, + "capability": { + "name": "capability", + "type": "portfolio_capability", + "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": { + "portfolio_capabilities_user_id_user_id_fk": { + "name": "portfolio_capabilities_user_id_user_id_fk", + "tableFrom": "portfolio_capabilities", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "portfolio_capabilities_portfolio_id_portfolio_id_fk": { + "name": "portfolio_capabilities_portfolio_id_portfolio_id_fk", + "tableFrom": "portfolio_capabilities", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "portfolio_capabilities_user_id_portfolio_id_capability_unique": { + "name": "portfolio_capabilities_user_id_portfolio_id_capability_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "portfolio_id", + "capability" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.portfolioInvitations": { + "name": "portfolioInvitations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "invited_by_user_id": { + "name": "invited_by_user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "portfolioInvitations_portfolio_id_portfolio_id_fk": { + "name": "portfolioInvitations_portfolio_id_portfolio_id_fk", + "tableFrom": "portfolioInvitations", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "portfolioInvitations_invited_by_user_id_user_id_fk": { + "name": "portfolioInvitations_invited_by_user_id_user_id_fk", + "tableFrom": "portfolioInvitations", + "tableTo": "user", + "columnsFrom": [ + "invited_by_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "portfolio_invitations_portfolio_email_unique": { + "name": "portfolio_invitations_portfolio_email_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "email" + ] + } + }, + "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.project": { + "name": "project", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "organisation_id": { + "name": "organisation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "project_type_id": { + "name": "project_type_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start_date": { + "name": "start_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "end_date": { + "name": "end_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "domna_admin_access": { + "name": "domna_admin_access", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "sharepoint_base_url": { + "name": "sharepoint_base_url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "sharepoint_sub_folder_template": { + "name": "sharepoint_sub_folder_template", + "type": "varchar", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "project_organisation_id_organisation_id_fk": { + "name": "project_organisation_id_organisation_id_fk", + "tableFrom": "project", + "tableTo": "organisation", + "columnsFrom": [ + "organisation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_project_type_id_project_type_id_fk": { + "name": "project_project_type_id_project_type_id_fk", + "tableFrom": "project", + "tableTo": "project_type", + "columnsFrom": [ + "project_type_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_property": { + "name": "project_property", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "project_property_project_id_project_id_fk": { + "name": "project_property_project_id_project_id_fk", + "tableFrom": "project_property", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_property_property_id_property_id_fk": { + "name": "project_property_property_id_property_id_fk", + "tableFrom": "project_property", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "project_property_project_id_property_id_unique": { + "name": "project_property_project_id_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "project_id", + "property_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_type": { + "name": "project_type", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_workstream": { + "name": "project_workstream", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "workstream_id": { + "name": "workstream_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "current_stage_id": { + "name": "current_stage_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "project_workstream_project_id_project_id_fk": { + "name": "project_workstream_project_id_project_id_fk", + "tableFrom": "project_workstream", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_workstream_workstream_id_workstream_id_fk": { + "name": "project_workstream_workstream_id_workstream_id_fk", + "tableFrom": "project_workstream", + "tableTo": "workstream", + "columnsFrom": [ + "workstream_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_workstream_current_stage_id_project_workstream_stage_id_fk": { + "name": "project_workstream_current_stage_id_project_workstream_stage_id_fk", + "tableFrom": "project_workstream", + "tableTo": "project_workstream_stage", + "columnsFrom": [ + "current_stage_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_workstream_contractor": { + "name": "project_workstream_contractor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_workstream_id": { + "name": "project_workstream_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "organisation_id": { + "name": "organisation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "update_stages_permission": { + "name": "update_stages_permission", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "upload_documents_permission": { + "name": "upload_documents_permission", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "assigned_at": { + "name": "assigned_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "project_workstream_contractor_project_workstream_id_project_workstream_id_fk": { + "name": "project_workstream_contractor_project_workstream_id_project_workstream_id_fk", + "tableFrom": "project_workstream_contractor", + "tableTo": "project_workstream", + "columnsFrom": [ + "project_workstream_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_workstream_contractor_organisation_id_organisation_id_fk": { + "name": "project_workstream_contractor_organisation_id_organisation_id_fk", + "tableFrom": "project_workstream_contractor", + "tableTo": "organisation", + "columnsFrom": [ + "organisation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_workstream_evidence_requirement": { + "name": "project_workstream_evidence_requirement", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_workstream_id": { + "name": "project_workstream_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "file_type": { + "name": "file_type", + "type": "file_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "project_workstream_stage_id": { + "name": "project_workstream_stage_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "required": { + "name": "required", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "naming_rule": { + "name": "naming_rule", + "type": "varchar", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "project_workstream_evidence_requirement_project_workstream_id_project_workstream_id_fk": { + "name": "project_workstream_evidence_requirement_project_workstream_id_project_workstream_id_fk", + "tableFrom": "project_workstream_evidence_requirement", + "tableTo": "project_workstream", + "columnsFrom": [ + "project_workstream_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_workstream_evidence_requirement_project_workstream_stage_id_project_workstream_stage_id_fk": { + "name": "project_workstream_evidence_requirement_project_workstream_stage_id_project_workstream_stage_id_fk", + "tableFrom": "project_workstream_evidence_requirement", + "tableTo": "project_workstream_stage", + "columnsFrom": [ + "project_workstream_stage_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_workstream_stage": { + "name": "project_workstream_stage", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_workstream_id": { + "name": "project_workstream_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "start_date": { + "name": "start_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "due_date": { + "name": "due_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "last_updated": { + "name": "last_updated", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status_description": { + "name": "status_description", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "project_workstream_stage_project_workstream_id_project_workstream_id_fk": { + "name": "project_workstream_stage_project_workstream_id_project_workstream_id_fk", + "tableFrom": "project_workstream_stage", + "tableTo": "project_workstream", + "columnsFrom": [ + "project_workstream_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.work_order": { + "name": "work_order", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "reference": { + "name": "reference", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "project_workstream_contractor_id": { + "name": "project_workstream_contractor_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "project_workstream_stage_id": { + "name": "project_workstream_stage_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "forecast_end": { + "name": "forecast_end", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "priority": { + "name": "priority", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "work_order_project_workstream_contractor_id_project_workstream_contractor_id_fk": { + "name": "work_order_project_workstream_contractor_id_project_workstream_contractor_id_fk", + "tableFrom": "work_order", + "tableTo": "project_workstream_contractor", + "columnsFrom": [ + "project_workstream_contractor_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "work_order_property_id_property_id_fk": { + "name": "work_order_property_id_property_id_fk", + "tableFrom": "work_order", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "work_order_project_workstream_stage_id_project_workstream_stage_id_fk": { + "name": "work_order_project_workstream_stage_id_project_workstream_stage_id_fk", + "tableFrom": "work_order", + "tableTo": "project_workstream_stage", + "columnsFrom": [ + "project_workstream_stage_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "work_order_reference_unique": { + "name": "work_order_reference_unique", + "nullsNotDistinct": false, + "columns": [ + "reference" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workstream": { + "name": "workstream", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_overrides": { + "name": "property_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "building_part": { + "name": "building_part", + "type": "smallint", + "primaryKey": false, + "notNull": true + }, + "override_component": { + "name": "override_component", + "type": "override_component", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "override_value": { + "name": "override_value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "original_spreadsheet_description": { + "name": "original_spreadsheet_description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "property_overrides_property_id_property_id_fk": { + "name": "property_overrides_property_id_property_id_fk", + "tableFrom": "property_overrides", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "property_overrides_portfolio_id_portfolio_id_fk": { + "name": "property_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "property_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "property_overrides_property_component_part_unique": { + "name": "property_overrides_property_component_part_unique", + "nullsNotDistinct": false, + "columns": [ + "property_id", + "override_component", + "building_part" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_building_part": { + "name": "epc_building_part", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "construction_age_band": { + "name": "construction_age_band", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "wall_construction": { + "name": "wall_construction", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "wall_insulation_type": { + "name": "wall_insulation_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "wall_thickness_measured": { + "name": "wall_thickness_measured", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "party_wall_construction": { + "name": "party_wall_construction", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "building_part_number": { + "name": "building_part_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "wall_dry_lined": { + "name": "wall_dry_lined", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "wall_thickness_mm": { + "name": "wall_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "wall_insulation_thickness": { + "name": "wall_insulation_thickness", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "wall_insulation_thermal_conductivity": { + "name": "wall_insulation_thermal_conductivity", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "floor_heat_loss": { + "name": "floor_heat_loss", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "floor_insulation_thickness": { + "name": "floor_insulation_thickness", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "flat_roof_insulation_thickness": { + "name": "flat_roof_insulation_thickness", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "floor_type": { + "name": "floor_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "floor_construction_type": { + "name": "floor_construction_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "floor_insulation_type_str": { + "name": "floor_insulation_type_str", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "floor_u_value_known": { + "name": "floor_u_value_known", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "roof_construction": { + "name": "roof_construction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "roof_insulation_location": { + "name": "roof_insulation_location", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "roof_insulation_thickness": { + "name": "roof_insulation_thickness", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "rafter_insulation_thickness": { + "name": "rafter_insulation_thickness", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "roof_construction_type": { + "name": "roof_construction_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "curtain_wall_age": { + "name": "curtain_wall_age", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "wall_is_basement": { + "name": "wall_is_basement", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "wall_u_value": { + "name": "wall_u_value", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_area": { + "name": "alt_wall_1_area", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_dry_lined": { + "name": "alt_wall_1_dry_lined", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_construction": { + "name": "alt_wall_1_construction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_insulation_type": { + "name": "alt_wall_1_insulation_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_thickness_measured": { + "name": "alt_wall_1_thickness_measured", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_insulation_thickness": { + "name": "alt_wall_1_insulation_thickness", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_is_sheltered": { + "name": "alt_wall_1_is_sheltered", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_u_value": { + "name": "alt_wall_1_u_value", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_thickness_mm": { + "name": "alt_wall_1_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_is_basement": { + "name": "alt_wall_1_is_basement", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_area": { + "name": "alt_wall_2_area", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_dry_lined": { + "name": "alt_wall_2_dry_lined", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_construction": { + "name": "alt_wall_2_construction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_insulation_type": { + "name": "alt_wall_2_insulation_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_thickness_measured": { + "name": "alt_wall_2_thickness_measured", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_insulation_thickness": { + "name": "alt_wall_2_insulation_thickness", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_is_sheltered": { + "name": "alt_wall_2_is_sheltered", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_u_value": { + "name": "alt_wall_2_u_value", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_thickness_mm": { + "name": "alt_wall_2_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_is_basement": { + "name": "alt_wall_2_is_basement", + "type": "boolean", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "ix_epc_building_part_epc_property": { + "name": "ix_epc_building_part_epc_property", + "columns": [ + { + "expression": "epc_property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_building_part_epc_property_id_epc_property_id_fk": { + "name": "epc_building_part_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_building_part", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_energy_element": { + "name": "epc_energy_element", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "element_type": { + "name": "element_type", + "type": "energy_element_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "energy_efficiency_rating": { + "name": "energy_efficiency_rating", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "environmental_efficiency_rating": { + "name": "environmental_efficiency_rating", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "ix_epc_energy_element_epc_property": { + "name": "ix_epc_energy_element_epc_property", + "columns": [ + { + "expression": "epc_property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_energy_element_epc_property_id_epc_property_id_fk": { + "name": "epc_energy_element_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_energy_element", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_flat_details": { + "name": "epc_flat_details", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "level": { + "name": "level", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "top_storey": { + "name": "top_storey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "flat_location": { + "name": "flat_location", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "heat_loss_corridor": { + "name": "heat_loss_corridor", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "storey_count": { + "name": "storey_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "unheated_corridor_length_m": { + "name": "unheated_corridor_length_m", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_flat_details_epc_property_id_epc_property_id_fk": { + "name": "epc_flat_details_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_flat_details", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_flat_details_epc_property_id_unique": { + "name": "epc_flat_details_epc_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "epc_property_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_floor_dimension": { + "name": "epc_floor_dimension", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_building_part_id": { + "name": "epc_building_part_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "floor": { + "name": "floor", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "room_height_m": { + "name": "room_height_m", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "total_floor_area_m2": { + "name": "total_floor_area_m2", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "party_wall_length_m": { + "name": "party_wall_length_m", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "heat_loss_perimeter_m": { + "name": "heat_loss_perimeter_m", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "floor_insulation": { + "name": "floor_insulation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "floor_construction": { + "name": "floor_construction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "is_exposed_floor": { + "name": "is_exposed_floor", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_above_partially_heated_space": { + "name": "is_above_partially_heated_space", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "ix_epc_floor_dimension_building_part": { + "name": "ix_epc_floor_dimension_building_part", + "columns": [ + { + "expression": "epc_building_part_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_floor_dimension_epc_building_part_id_epc_building_part_id_fk": { + "name": "epc_floor_dimension_epc_building_part_id_epc_building_part_id_fk", + "tableFrom": "epc_floor_dimension", + "tableTo": "epc_building_part", + "columnsFrom": [ + "epc_building_part_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_main_heating_detail": { + "name": "epc_main_heating_detail", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "has_fghrs": { + "name": "has_fghrs", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "main_fuel_type": { + "name": "main_fuel_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "heat_emitter_type": { + "name": "heat_emitter_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "emitter_temperature": { + "name": "emitter_temperature", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "main_heating_control": { + "name": "main_heating_control", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "fan_flue_present": { + "name": "fan_flue_present", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "boiler_flue_type": { + "name": "boiler_flue_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "boiler_ignition_type": { + "name": "boiler_ignition_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "central_heating_pump_age": { + "name": "central_heating_pump_age", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "central_heating_pump_age_str": { + "name": "central_heating_pump_age_str", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "main_heating_index_number": { + "name": "main_heating_index_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "sap_main_heating_code": { + "name": "sap_main_heating_code", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "main_heating_number": { + "name": "main_heating_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "main_heating_category": { + "name": "main_heating_category", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "main_heating_fraction": { + "name": "main_heating_fraction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "main_heating_data_source": { + "name": "main_heating_data_source", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "condensing": { + "name": "condensing", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "weather_compensator": { + "name": "weather_compensator", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "community_heating_boiler_fuel_type": { + "name": "community_heating_boiler_fuel_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "community_heating_chp_fraction": { + "name": "community_heating_chp_fraction", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "ix_epc_main_heating_detail_epc_property": { + "name": "ix_epc_main_heating_detail_epc_property", + "columns": [ + { + "expression": "epc_property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_main_heating_detail_epc_property_id_epc_property_id_fk": { + "name": "epc_main_heating_detail_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_main_heating_detail", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_photovoltaic_array": { + "name": "epc_photovoltaic_array", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "array_index": { + "name": "array_index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "peak_power": { + "name": "peak_power", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "pitch": { + "name": "pitch", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "overshading": { + "name": "overshading", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "orientation": { + "name": "orientation", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_photovoltaic_array_epc_property_id_epc_property_id_fk": { + "name": "epc_photovoltaic_array_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_photovoltaic_array", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_property": { + "name": "epc_property", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "uploaded_file_id": { + "name": "uploaded_file_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'lodged'" + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "uprn_source": { + "name": "uprn_source", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "report_reference": { + "name": "report_reference", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "report_type": { + "name": "report_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "assessment_type": { + "name": "assessment_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sap_version": { + "name": "sap_version", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "schema_type": { + "name": "schema_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "schema_versions_original": { + "name": "schema_versions_original", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "calculation_software_version": { + "name": "calculation_software_version", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address_line_1": { + "name": "address_line_1", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "address_line_2": { + "name": "address_line_2", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "post_town": { + "name": "post_town", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "region_code": { + "name": "region_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "country_code": { + "name": "country_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "language_code": { + "name": "language_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dwelling_type": { + "name": "dwelling_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "property_type": { + "name": "property_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "built_form": { + "name": "built_form", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tenure": { + "name": "tenure", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "transaction_type": { + "name": "transaction_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "inspection_date": { + "name": "inspection_date", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "completion_date": { + "name": "completion_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "registration_date": { + "name": "registration_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "total_floor_area_m2": { + "name": "total_floor_area_m2", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "measurement_type": { + "name": "measurement_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "solar_water_heating": { + "name": "solar_water_heating", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "has_hot_water_cylinder": { + "name": "has_hot_water_cylinder", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "has_fixed_air_conditioning": { + "name": "has_fixed_air_conditioning", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "has_conservatory": { + "name": "has_conservatory", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "has_heated_separate_conservatory": { + "name": "has_heated_separate_conservatory", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "conservatory_type": { + "name": "conservatory_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "conservatory_floor_area_m2": { + "name": "conservatory_floor_area_m2", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "conservatory_glazed_perimeter_m": { + "name": "conservatory_glazed_perimeter_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "conservatory_double_glazed": { + "name": "conservatory_double_glazed", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "conservatory_thermally_separated": { + "name": "conservatory_thermally_separated", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "conservatory_room_height_storeys": { + "name": "conservatory_room_height_storeys", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "door_count": { + "name": "door_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "wet_rooms_count": { + "name": "wet_rooms_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "extensions_count": { + "name": "extensions_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "heated_rooms_count": { + "name": "heated_rooms_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "open_chimneys_count": { + "name": "open_chimneys_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "habitable_rooms_count": { + "name": "habitable_rooms_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "insulated_door_count": { + "name": "insulated_door_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "cfl_fixed_lighting_bulbs_count": { + "name": "cfl_fixed_lighting_bulbs_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "led_fixed_lighting_bulbs_count": { + "name": "led_fixed_lighting_bulbs_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "incandescent_fixed_lighting_bulbs_count": { + "name": "incandescent_fixed_lighting_bulbs_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "blocked_chimneys_count": { + "name": "blocked_chimneys_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "draughtproofed_door_count": { + "name": "draughtproofed_door_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "energy_rating_average": { + "name": "energy_rating_average", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "low_energy_fixed_lighting_bulbs_count": { + "name": "low_energy_fixed_lighting_bulbs_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "fixed_lighting_outlets_count": { + "name": "fixed_lighting_outlets_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "low_energy_fixed_lighting_outlets_count": { + "name": "low_energy_fixed_lighting_outlets_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "number_of_storeys": { + "name": "number_of_storeys", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "any_unheated_rooms": { + "name": "any_unheated_rooms", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "hydro": { + "name": "hydro", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "photovoltaic_array": { + "name": "photovoltaic_array", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "waste_water_heat_recovery": { + "name": "waste_water_heat_recovery", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pressure_test": { + "name": "pressure_test", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "pressure_test_certificate_number": { + "name": "pressure_test_certificate_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "percent_draughtproofed": { + "name": "percent_draughtproofed", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "insulated_door_u_value": { + "name": "insulated_door_u_value", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "multiple_glazed_proportion": { + "name": "multiple_glazed_proportion", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "windows_transmission_u_value": { + "name": "windows_transmission_u_value", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "windows_transmission_data_source": { + "name": "windows_transmission_data_source", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "windows_transmission_solar_transmittance": { + "name": "windows_transmission_solar_transmittance", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_gas_connection_available": { + "name": "energy_gas_connection_available", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "energy_meter_type": { + "name": "energy_meter_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "energy_pv_battery_count": { + "name": "energy_pv_battery_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "energy_wind_turbines_count": { + "name": "energy_wind_turbines_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "energy_gas_smart_meter_present": { + "name": "energy_gas_smart_meter_present", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "energy_is_dwelling_export_capable": { + "name": "energy_is_dwelling_export_capable", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "energy_wind_turbines_terrain_type": { + "name": "energy_wind_turbines_terrain_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "energy_electricity_smart_meter_present": { + "name": "energy_electricity_smart_meter_present", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "energy_pv_connection": { + "name": "energy_pv_connection", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "energy_pv_percent_roof_area": { + "name": "energy_pv_percent_roof_area", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "energy_pv_battery_capacity": { + "name": "energy_pv_battery_capacity", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_wind_turbine_hub_height": { + "name": "energy_wind_turbine_hub_height", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_wind_turbine_rotor_diameter": { + "name": "energy_wind_turbine_rotor_diameter", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_pv_diverter_present": { + "name": "energy_pv_diverter_present", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "heating_cylinder_size": { + "name": "heating_cylinder_size", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_water_heating_code": { + "name": "heating_water_heating_code", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_water_heating_fuel": { + "name": "heating_water_heating_fuel", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_immersion_heating_type": { + "name": "heating_immersion_heating_type", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_insulation_type": { + "name": "heating_cylinder_insulation_type", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_thermostat": { + "name": "heating_cylinder_thermostat", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "heating_secondary_fuel_type": { + "name": "heating_secondary_fuel_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_secondary_heating_type": { + "name": "heating_secondary_heating_type", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_insulation_thickness_mm": { + "name": "heating_cylinder_insulation_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_volume_measured_l": { + "name": "heating_cylinder_volume_measured_l", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_heat_loss": { + "name": "heating_cylinder_heat_loss", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "heating_wwhrs_index_number_1": { + "name": "heating_wwhrs_index_number_1", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_wwhrs_index_number_2": { + "name": "heating_wwhrs_index_number_2", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_shower_outlet_type": { + "name": "heating_shower_outlet_type", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_shower_wwhrs": { + "name": "heating_shower_wwhrs", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_type": { + "name": "ventilation_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ventilation_draught_lobby": { + "name": "ventilation_draught_lobby", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "ventilation_pressure_test": { + "name": "ventilation_pressure_test", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ventilation_open_flues_count": { + "name": "ventilation_open_flues_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_closed_flues_count": { + "name": "ventilation_closed_flues_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_boiler_flues_count": { + "name": "ventilation_boiler_flues_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_other_flues_count": { + "name": "ventilation_other_flues_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_extract_fans_count": { + "name": "ventilation_extract_fans_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_passive_vents_count": { + "name": "ventilation_passive_vents_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_flueless_gas_fires_count": { + "name": "ventilation_flueless_gas_fires_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_in_pcdf_database": { + "name": "ventilation_in_pcdf_database", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "mechanical_ventilation": { + "name": "mechanical_ventilation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_duct_type": { + "name": "mechanical_vent_duct_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_duct_placement": { + "name": "mechanical_vent_duct_placement", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_duct_insulation": { + "name": "mechanical_vent_duct_insulation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_ventilation_index_number": { + "name": "mechanical_ventilation_index_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_measured_installation": { + "name": "mechanical_vent_measured_installation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_duct_insulation_level": { + "name": "mechanical_vent_duct_insulation_level", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "addendum_stone_walls": { + "name": "addendum_stone_walls", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "addendum_system_build": { + "name": "addendum_system_build", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "addendum_numbers": { + "name": "addendum_numbers", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_number_baths": { + "name": "heating_number_baths", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_number_baths_wwhrs": { + "name": "heating_number_baths_wwhrs", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_electric_shower_count": { + "name": "heating_electric_shower_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_mixer_shower_count": { + "name": "heating_mixer_shower_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_present": { + "name": "ventilation_present", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "ventilation_sheltered_sides": { + "name": "ventilation_sheltered_sides", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_has_suspended_timber_floor": { + "name": "ventilation_has_suspended_timber_floor", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "ventilation_suspended_timber_floor_sealed": { + "name": "ventilation_suspended_timber_floor_sealed", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "ventilation_has_draught_lobby": { + "name": "ventilation_has_draught_lobby", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "ventilation_air_permeability_ap4_m3_h_m2": { + "name": "ventilation_air_permeability_ap4_m3_h_m2", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "ventilation_air_permeability_ap50_m3_h_m2": { + "name": "ventilation_air_permeability_ap50_m3_h_m2", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "ventilation_mechanical_ventilation_kind": { + "name": "ventilation_mechanical_ventilation_kind", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "uq_epc_property_property_portfolio": { + "name": "uq_epc_property_property_portfolio", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "ix_epc_property_property_source": { + "name": "ix_epc_property_property_source", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_property_property_id_property_id_fk": { + "name": "epc_property_property_id_property_id_fk", + "tableFrom": "epc_property", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "epc_property_portfolio_id_portfolio_id_fk": { + "name": "epc_property_portfolio_id_portfolio_id_fk", + "tableFrom": "epc_property", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "epc_property_uploaded_file_id_uploaded_files_id_fk": { + "name": "epc_property_uploaded_file_id_uploaded_files_id_fk", + "tableFrom": "epc_property", + "tableTo": "uploaded_files", + "columnsFrom": [ + "uploaded_file_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_property_uploaded_file_id_unique": { + "name": "epc_property_uploaded_file_id_unique", + "nullsNotDistinct": false, + "columns": [ + "uploaded_file_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_property_energy_performance": { + "name": "epc_property_energy_performance", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "energy_rating_current": { + "name": "energy_rating_current", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "energy_consumption_current": { + "name": "energy_consumption_current", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "environmental_impact_current": { + "name": "environmental_impact_current", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_cost_current": { + "name": "heating_cost_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lighting_cost_current": { + "name": "lighting_cost_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "hot_water_cost_current": { + "name": "hot_water_cost_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_emissions_current": { + "name": "co2_emissions_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_emissions_current_per_floor_area": { + "name": "co2_emissions_current_per_floor_area", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "current_energy_efficiency_band": { + "name": "current_energy_efficiency_band", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "energy_rating_potential": { + "name": "energy_rating_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_consumption_potential": { + "name": "energy_consumption_potential", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "environmental_impact_potential": { + "name": "environmental_impact_potential", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_cost_potential": { + "name": "heating_cost_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lighting_cost_potential": { + "name": "lighting_cost_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "hot_water_cost_potential": { + "name": "hot_water_cost_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_emissions_potential": { + "name": "co2_emissions_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "potential_energy_efficiency_band": { + "name": "potential_energy_efficiency_band", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_property_energy_performance_epc_property_id_epc_property_id_fk": { + "name": "epc_property_energy_performance_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_property_energy_performance", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_property_energy_performance_epc_property_id_unique": { + "name": "epc_property_energy_performance_epc_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "epc_property_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_renewable_heat_incentive": { + "name": "epc_renewable_heat_incentive", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "space_heating_kwh": { + "name": "space_heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "water_heating_kwh": { + "name": "water_heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "impact_of_loft_insulation_kwh": { + "name": "impact_of_loft_insulation_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "impact_of_cavity_insulation_kwh": { + "name": "impact_of_cavity_insulation_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "impact_of_solid_wall_insulation_kwh": { + "name": "impact_of_solid_wall_insulation_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_renewable_heat_incentive_epc_property_id_epc_property_id_fk": { + "name": "epc_renewable_heat_incentive_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_renewable_heat_incentive", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_renewable_heat_incentive_epc_property_id_unique": { + "name": "epc_renewable_heat_incentive_epc_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "epc_property_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_roof_window": { + "name": "epc_roof_window", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "roof_window_index": { + "name": "roof_window_index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "area_m2": { + "name": "area_m2", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "u_value_raw": { + "name": "u_value_raw", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "orientation": { + "name": "orientation", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "pitch_deg": { + "name": "pitch_deg", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "g_perpendicular": { + "name": "g_perpendicular", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "frame_factor": { + "name": "frame_factor", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "glazing_type": { + "name": "glazing_type", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "window_location": { + "name": "window_location", + "type": "jsonb", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "uq_epc_roof_window_property_index": { + "name": "uq_epc_roof_window_property_index", + "columns": [ + { + "expression": "epc_property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "roof_window_index", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_roof_window_epc_property_id_epc_property_id_fk": { + "name": "epc_roof_window_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_roof_window", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_room_in_roof": { + "name": "epc_room_in_roof", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_building_part_id": { + "name": "epc_building_part_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "floor_area": { + "name": "floor_area", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "construction_age_band": { + "name": "construction_age_band", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "common_wall_length_m": { + "name": "common_wall_length_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "common_wall_height_m": { + "name": "common_wall_height_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "gable_1_length_m": { + "name": "gable_1_length_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "gable_1_height_m": { + "name": "gable_1_height_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "gable_2_length_m": { + "name": "gable_2_length_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "gable_2_height_m": { + "name": "gable_2_height_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_room_in_roof_epc_building_part_id_epc_building_part_id_fk": { + "name": "epc_room_in_roof_epc_building_part_id_epc_building_part_id_fk", + "tableFrom": "epc_room_in_roof", + "tableTo": "epc_building_part", + "columnsFrom": [ + "epc_building_part_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_room_in_roof_epc_building_part_id_unique": { + "name": "epc_room_in_roof_epc_building_part_id_unique", + "nullsNotDistinct": false, + "columns": [ + "epc_building_part_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_room_in_roof_surface": { + "name": "epc_room_in_roof_surface", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_room_in_roof_id": { + "name": "epc_room_in_roof_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "surface_index": { + "name": "surface_index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "area_m2": { + "name": "area_m2", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "insulation_thickness_mm": { + "name": "insulation_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "insulation_type": { + "name": "insulation_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "u_value": { + "name": "u_value", + "type": "double precision", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "uq_epc_room_in_roof_surface_index": { + "name": "uq_epc_room_in_roof_surface_index", + "columns": [ + { + "expression": "epc_room_in_roof_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "surface_index", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_room_in_roof_surface_epc_room_in_roof_id_epc_room_in_roof_id_fk": { + "name": "epc_room_in_roof_surface_epc_room_in_roof_id_epc_room_in_roof_id_fk", + "tableFrom": "epc_room_in_roof_surface", + "tableTo": "epc_room_in_roof", + "columnsFrom": [ + "epc_room_in_roof_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_window": { + "name": "epc_window", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "glazing_gap": { + "name": "glazing_gap", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "orientation": { + "name": "orientation", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "window_type": { + "name": "window_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "glazing_type": { + "name": "glazing_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "window_width": { + "name": "window_width", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "window_height": { + "name": "window_height", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "draught_proofed": { + "name": "draught_proofed", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "window_location": { + "name": "window_location", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "window_wall_type": { + "name": "window_wall_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "permanent_shutters_present": { + "name": "permanent_shutters_present", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "frame_material": { + "name": "frame_material", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "frame_factor": { + "name": "frame_factor", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "permanent_shutters_insulated": { + "name": "permanent_shutters_insulated", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "transmission_u_value": { + "name": "transmission_u_value", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "transmission_data_source": { + "name": "transmission_data_source", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "transmission_solar_transmittance": { + "name": "transmission_solar_transmittance", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_window_epc_property_id_epc_property_id_fk": { + "name": "epc_window_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_window", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_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 + }, + "certificate_number": { + "name": "certificate_number", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "landlord_property_id": { + "name": "landlord_property_id", + "type": "text", + "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 + }, + "user_inputted_address": { + "name": "user_inputted_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_inputted_postcode": { + "name": "user_inputted_postcode", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lexiscore": { + "name": "lexiscore", + "type": "real", + "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 + }, + "installed_measures_sap_point_adjustment": { + "name": "installed_measures_sap_point_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "is_sap_points_adjusted_for_installed_measures": { + "name": "is_sap_points_adjusted_for_installed_measures", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "original_sap_points": { + "name": "original_sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lodged_sap_points": { + "name": "lodged_sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lodged_epc_rating": { + "name": "lodged_epc_rating", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "marked_for_deletion": { + "name": "marked_for_deletion", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "uq_property_portfolio_uprn": { + "name": "uq_property_portfolio_uprn", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"property\".\"uprn\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "ix_property_portfolio": { + "name": "ix_property_portfolio", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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_baseline_performance": { + "name": "property_baseline_performance", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "lodged_sap_score": { + "name": "lodged_sap_score", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "lodged_epc_band": { + "name": "lodged_epc_band", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "lodged_co2_emissions_t_per_yr": { + "name": "lodged_co2_emissions_t_per_yr", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lodged_primary_energy_intensity_kwh_per_m2_yr": { + "name": "lodged_primary_energy_intensity_kwh_per_m2_yr", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "effective_sap_score": { + "name": "effective_sap_score", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "effective_epc_band": { + "name": "effective_epc_band", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "effective_co2_emissions_t_per_yr": { + "name": "effective_co2_emissions_t_per_yr", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "effective_primary_energy_intensity_kwh_per_m2_yr": { + "name": "effective_primary_energy_intensity_kwh_per_m2_yr", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "rebaseline_reason": { + "name": "rebaseline_reason", + "type": "rebaseline_reason", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "space_heating_kwh": { + "name": "space_heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "water_heating_kwh": { + "name": "water_heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "fuel_rates_period": { + "name": "fuel_rates_period", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "heating_kwh": { + "name": "heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "heating_cost_gbp": { + "name": "heating_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "hot_water_kwh": { + "name": "hot_water_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "hot_water_cost_gbp": { + "name": "hot_water_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lighting_kwh": { + "name": "lighting_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lighting_cost_gbp": { + "name": "lighting_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "appliances_kwh": { + "name": "appliances_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "appliances_cost_gbp": { + "name": "appliances_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cooking_kwh": { + "name": "cooking_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cooking_cost_gbp": { + "name": "cooking_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "pumps_fans_kwh": { + "name": "pumps_fans_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "pumps_fans_cost_gbp": { + "name": "pumps_fans_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cooling_kwh": { + "name": "cooling_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cooling_cost_gbp": { + "name": "cooling_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "standing_charges_gbp": { + "name": "standing_charges_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "seg_credit_gbp": { + "name": "seg_credit_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "total_annual_bill_gbp": { + "name": "total_annual_bill_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "property_baseline_performance_property_id_property_id_fk": { + "name": "property_baseline_performance_property_id_property_id_fk", + "tableFrom": "property_baseline_performance", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "property_baseline_performance_property_id_unique": { + "name": "property_baseline_performance_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "property_id" + ] + } + }, + "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 + }, + "lodgement_date": { + "name": "lodgement_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "is_expired": { + "name": "is_expired", + "type": "boolean", + "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 + }, + "sap_05_overwritten": { + "name": "sap_05_overwritten", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "sap_05_score": { + "name": "sap_05_score", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "sap_05_epc_rating": { + "name": "sap_05_epc_rating", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": 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 + }, + "original_co2_emissions": { + "name": "original_co2_emissions", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "original_primary_energy_consumption": { + "name": "original_primary_energy_consumption", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "original_current_energy_demand": { + "name": "original_current_energy_demand", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "original_current_energy_demand_heating_hotwater": { + "name": "original_current_energy_demand_heating_hotwater", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "installed_measures_co2_adjustment": { + "name": "installed_measures_co2_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "installed_measures_energy_demand_adjustment": { + "name": "installed_measures_energy_demand_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "installed_measures_total_energy_bill_adjustment": { + "name": "installed_measures_total_energy_bill_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "installed_measures_heat_demand_adjustment": { + "name": "installed_measures_heat_demand_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "is_epc_adjusted_for_installed_measures": { + "name": "is_epc_adjusted_for_installed_measures", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "lodged_co2_emissions": { + "name": "lodged_co2_emissions", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lodged_heat_demand": { + "name": "lodged_heat_demand", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "has_been_remodelled": { + "name": "has_been_remodelled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "environment_impact_current": { + "name": "environment_impact_current", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "uq_property_details_epc_property_portfolio": { + "name": "uq_property_details_epc_property_portfolio", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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": { + "uq_property_details_spatial_uprn": { + "name": "uq_property_details_spatial_uprn", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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.installed_measure": { + "name": "installed_measure", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "measure_type": { + "name": "measure_type", + "type": "measure_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "installed_at": { + "name": "installed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "sap_points": { + "name": "sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "carbon_savings": { + "name": "carbon_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "kwh_savings": { + "name": "kwh_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "bill_savings": { + "name": "bill_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "heat_demand_savings": { + "name": "heat_demand_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + } + }, + "indexes": { + "idx_installed_measure_uprn": { + "name": "idx_installed_measure_uprn", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_installed_measure_uprn_active": { + "name": "idx_installed_measure_uprn_active", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"installed_measure\".\"is_active\" = true", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_installed_measure_measure_type": { + "name": "idx_installed_measure_measure_type", + "columns": [ + { + "expression": "measure_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_installed_measure_uprn_measure": { + "name": "idx_installed_measure_uprn_measure", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "measure_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"installed_measure\".\"is_active\" = true", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "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 + }, + "post_sap_points": { + "name": "post_sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "post_epc_rating": { + "name": "post_epc_rating", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "post_co2_emissions": { + "name": "post_co2_emissions", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_savings": { + "name": "co2_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "post_energy_bill": { + "name": "post_energy_bill", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_bill_savings": { + "name": "energy_bill_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "post_energy_consumption": { + "name": "post_energy_consumption", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_consumption_savings": { + "name": "energy_consumption_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "valuation_post_retrofit": { + "name": "valuation_post_retrofit", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "valuation_increase": { + "name": "valuation_increase", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cost_of_works": { + "name": "cost_of_works", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "contingency_cost": { + "name": "contingency_cost", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "plan_type": { + "name": "plan_type", + "type": "plan_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_plan_portfolio_scenario": { + "name": "idx_plan_portfolio_scenario", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scenario_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_plan_latest_per_property": { + "name": "idx_plan_latest_per_property", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scenario_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_plan_property_default_latest": { + "name": "idx_plan_property_default_latest", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "where": "is_default = true", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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": { + "idx_plan_recommendations_plan_id": { + "name": "idx_plan_recommendations_plan_id", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_plan_recommendations_plan_rec": { + "name": "idx_plan_recommendations_plan_rec", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "recommendation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_plan_recommendations_recommendation_id": { + "name": "idx_plan_recommendations_recommendation_id", + "columns": [ + { + "expression": "recommendation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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 + }, + "plan_id": { + "name": "plan_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "material_id": { + "name": "material_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "material_quantity": { + "name": "material_quantity", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "material_quantity_unit": { + "name": "material_quantity_unit", + "type": "unit_quantity", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "material_depth": { + "name": "material_depth", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "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": { + "recommendation_property_id_idx": { + "name": "recommendation_property_id_idx", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_plan_id": { + "name": "idx_recommendation_plan_id", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_active_defaults": { + "name": "idx_recommendation_active_defaults", + "columns": [ + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"recommendation\".\"default\" = true AND \"recommendation\".\"already_installed\" = false", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_active_id_property": { + "name": "idx_recommendation_active_id_property", + "columns": [ + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"recommendation\".\"default\" = true AND \"recommendation\".\"already_installed\" = false", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_plan_default": { + "name": "idx_recommendation_plan_default", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "measure_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "estimated_cost", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"recommendation\".\"default\" = true AND \"recommendation\".\"already_installed\" = false", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_material_id": { + "name": "idx_recommendation_material_id", + "columns": [ + { + "expression": "material_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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" + }, + "recommendation_plan_id_plan_id_fk": { + "name": "recommendation_plan_id_plan_id_fk", + "tableFrom": "recommendation", + "tableTo": "plan", + "columnsFrom": [ + "plan_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "recommendation_material_id_material_id_fk": { + "name": "recommendation_material_id_material_id_fk", + "tableFrom": "recommendation", + "tableTo": "material", + "columnsFrom": [ + "material_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "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": { + "recommendation_materials_recommendation_id_idx": { + "name": "recommendation_materials_recommendation_id_idx", + "columns": [ + { + "expression": "recommendation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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": "cascade", + "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 + }, + "fabric_first": { + "name": "fabric_first", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "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.property_removal_requests": { + "name": "property_removal_requests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'removal'" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "requested_by": { + "name": "requested_by", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "requested_at": { + "name": "requested_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "reviewed_by": { + "name": "reviewed_by", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "reviewed_at": { + "name": "reviewed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "original_batch": { + "name": "original_batch", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_removal_requests_deal_id": { + "name": "idx_removal_requests_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_removal_requests_portfolio_id": { + "name": "idx_removal_requests_portfolio_id", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "property_removal_requests_portfolio_id_portfolio_id_fk": { + "name": "property_removal_requests_portfolio_id_portfolio_id_fk", + "tableFrom": "property_removal_requests", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "property_removal_requests_requested_by_user_id_fk": { + "name": "property_removal_requests_requested_by_user_id_fk", + "tableFrom": "property_removal_requests", + "tableTo": "user", + "columnsFrom": [ + "requested_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "property_removal_requests_reviewed_by_user_id_fk": { + "name": "property_removal_requests_reviewed_by_user_id_fk", + "tableFrom": "property_removal_requests", + "tableTo": "user", + "columnsFrom": [ + "reviewed_by" + ], + "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.survey_requests": { + "name": "survey_requests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "survey_type": { + "name": "survey_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "requested_by": { + "name": "requested_by", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "requested_at": { + "name": "requested_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "fulfilled_at": { + "name": "fulfilled_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_survey_requests_deal_id": { + "name": "idx_survey_requests_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_survey_requests_portfolio_id": { + "name": "idx_survey_requests_portfolio_id", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "survey_requests_portfolio_id_portfolio_id_fk": { + "name": "survey_requests_portfolio_id_portfolio_id_fk", + "tableFrom": "survey_requests", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "survey_requests_requested_by_user_id_fk": { + "name": "survey_requests_requested_by_user_id_fk", + "tableFrom": "survey_requests", + "tableTo": "user", + "columnsFrom": [ + "requested_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.portfolio_tag": { + "name": "portfolio_tag", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "colour": { + "name": "colour", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "uq_portfolio_tag_portfolio_lower_name": { + "name": "uq_portfolio_tag_portfolio_lower_name", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"name\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "portfolio_tag_portfolio_id_portfolio_id_fk": { + "name": "portfolio_tag_portfolio_id_portfolio_id_fk", + "tableFrom": "portfolio_tag", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_tag": { + "name": "property_tag", + "schema": "", + "columns": { + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "tag_id": { + "name": "tag_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "ix_property_tag_tag": { + "name": "ix_property_tag_tag", + "columns": [ + { + "expression": "tag_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "property_tag_property_id_property_id_fk": { + "name": "property_tag_property_id_property_id_fk", + "tableFrom": "property_tag", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "property_tag_tag_id_portfolio_tag_id_fk": { + "name": "property_tag_tag_id_portfolio_tag_id_fk", + "tableFrom": "property_tag", + "tableTo": "portfolio_tag", + "columnsFrom": [ + "tag_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "property_tag_property_id_tag_id_pk": { + "name": "property_tag_property_id_tag_id_pk", + "columns": [ + "property_id", + "tag_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sub_task": { + "name": "sub_task", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "task_id": { + "name": "task_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "job_started": { + "name": "job_started", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "job_completed": { + "name": "job_completed", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'In Progress'" + }, + "service": { + "name": "service", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "inputs": { + "name": "inputs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "outputs": { + "name": "outputs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cloud_logs_url": { + "name": "cloud_logs_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "sub_task_task_id_tasks_id_fk": { + "name": "sub_task_task_id_tasks_id_fk", + "tableFrom": "sub_task", + "tableTo": "tasks", + "columnsFrom": [ + "task_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tasks": { + "name": "tasks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "task_source": { + "name": "task_source", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "job_started": { + "name": "job_started", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "job_completed": { + "name": "job_completed", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'In Progress'" + }, + "service": { + "name": "service", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "source", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "source_id": { + "name": "source_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "inputs": { + "name": "inputs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team": { + "name": "team", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "uuid", + "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": { + "team_org_id_organisation_id_fk": { + "name": "team_org_id_organisation_id_fk", + "tableFrom": "team", + "tableTo": "organisation", + "columnsFrom": [ + "org_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_members": { + "name": "team_members", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "team_id": { + "name": "team_id", + "type": "uuid", + "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": { + "team_members_user_id_user_id_fk": { + "name": "team_members_user_id_user_id_fk", + "tableFrom": "team_members", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "team_members_team_id_team_id_fk": { + "name": "team_members_team_id_team_id_fk", + "tableFrom": "team_members", + "tableTo": "team", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_portfolio_permissions": { + "name": "team_portfolio_permissions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "team_id": { + "name": "team_id", + "type": "uuid", + "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": { + "team_portfolio_permissions_team_id_team_id_fk": { + "name": "team_portfolio_permissions_team_id_team_id_fk", + "tableFrom": "team_portfolio_permissions", + "tableTo": "team", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "team_portfolio_permissions_portfolio_id_portfolio_id_fk": { + "name": "team_portfolio_permissions_portfolio_id_portfolio_id_fk", + "tableFrom": "team_portfolio_permissions", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.uploaded_files": { + "name": "uploaded_files", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "s3_file_bucket": { + "name": "s3_file_bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "s3_file_key": { + "name": "s3_file_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "s3_upload_timestamp": { + "name": "s3_upload_timestamp", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "landlord_property_id": { + "name": "landlord_property_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "hubspot_listing_id": { + "name": "hubspot_listing_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "file_type": { + "name": "file_type", + "type": "file_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "file_source": { + "name": "file_source", + "type": "file_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uploaded_by": { + "name": "uploaded_by", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "work_order_id": { + "name": "work_order_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "project_workstream_evidence_requirement_id": { + "name": "project_workstream_evidence_requirement_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "uploaded_files_uploaded_by_user_id_fk": { + "name": "uploaded_files_uploaded_by_user_id_fk", + "tableFrom": "uploaded_files", + "tableTo": "user", + "columnsFrom": [ + "uploaded_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "uploaded_files_work_order_id_work_order_id_fk": { + "name": "uploaded_files_work_order_id_work_order_id_fk", + "tableFrom": "uploaded_files", + "tableTo": "work_order", + "columnsFrom": [ + "work_order_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "uploaded_files_project_workstream_evidence_requirement_id_project_workstream_evidence_requirement_id_fk": { + "name": "uploaded_files_project_workstream_evidence_requirement_id_project_workstream_evidence_requirement_id_fk", + "tableFrom": "uploaded_files", + "tableTo": "project_workstream_evidence_requirement", + "columnsFrom": [ + "project_workstream_evidence_requirement_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_defined_deal_measures": { + "name": "user_defined_deal_measures", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "user_defined_deal_measure_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "pushed_at": { + "name": "pushed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "confirmed_in_hubspot_at": { + "name": "confirmed_in_hubspot_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_user_defined_deal_measures_deal_id": { + "name": "idx_user_defined_deal_measures_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_user_defined_deal_measures_source": { + "name": "idx_user_defined_deal_measures_source", + "columns": [ + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_defined_deal_measures_created_by_user_id_user_id_fk": { + "name": "user_defined_deal_measures_created_by_user_id_user_id_fk", + "tableFrom": "user_defined_deal_measures", + "tableTo": "user", + "columnsFrom": [ + "created_by_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_portfolio_config": { + "name": "user_portfolio_config", + "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 + }, + "starred_at": { + "name": "starred_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "folder_id": { + "name": "folder_id", + "type": "bigint", + "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": { + "idx_user_portfolio_config_folder": { + "name": "idx_user_portfolio_config_folder", + "columns": [ + { + "expression": "folder_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_portfolio_config_user_id_user_id_fk": { + "name": "user_portfolio_config_user_id_user_id_fk", + "tableFrom": "user_portfolio_config", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_portfolio_config_portfolio_id_portfolio_id_fk": { + "name": "user_portfolio_config_portfolio_id_portfolio_id_fk", + "tableFrom": "user_portfolio_config", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_portfolio_config_folder_owner_fk": { + "name": "user_portfolio_config_folder_owner_fk", + "tableFrom": "user_portfolio_config", + "tableTo": "user_portfolio_folders", + "columnsFrom": [ + "folder_id", + "user_id" + ], + "columnsTo": [ + "id", + "user_id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_portfolio_config_user_portfolio_unique": { + "name": "user_portfolio_config_user_portfolio_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "portfolio_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_portfolio_folders": { + "name": "user_portfolio_folders", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "position": { + "name": "position", + "type": "integer", + "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": { + "idx_user_portfolio_folders_user_position": { + "name": "idx_user_portfolio_folders_user_position", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "position", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_portfolio_folders_user_id_user_id_fk": { + "name": "user_portfolio_folders_user_id_user_id_fk", + "tableFrom": "user_portfolio_folders", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_portfolio_folders_id_user_unique": { + "name": "user_portfolio_folders_id_user_unique", + "nullsNotDistinct": false, + "columns": [ + "id", + "user_id" + ] + } + }, + "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.authRateLimits": { + "name": "authRateLimits", + "schema": "", + "columns": { + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "count": { + "name": "count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "window_start": { + "name": "window_start", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "authRateLimits_scope_key_pk": { + "name": "authRateLimits_scope_key_pk", + "columns": [ + "scope", + "key" + ] + } + }, + "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 + }, + "code_hash": { + "name": "code_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.whlg": { + "name": "whlg", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.aspect_type": { + "name": "aspect_type", + "schema": "public", + "values": [ + "material", + "condition", + "type", + "area", + "configuration", + "presence", + "risk", + "severity", + "location", + "finish", + "insulation", + "pointing", + "spalling", + "lintels", + "cladding", + "category", + "quantity", + "adequacy", + "rating", + "strategy", + "extent", + "distribution", + "structure", + "covering", + "fire_rating", + "external_decoration", + "work_required", + "age_band", + "construction_type", + "classification", + "system" + ] + }, + "public.element_type": { + "name": "element_type", + "schema": "public", + "values": [ + "property", + "property_construction_type", + "property_classification", + "property_age_band", + "storey_count", + "floor_level", + "floor_level_front_door", + "accessible_housing_register", + "asbestos", + "quality_standard", + "ccu", + "passenger_lift", + "stairlift", + "disabled_hoist_tracking", + "disabled_facilities", + "steps_to_front_door", + "roof", + "pitched_roof_covering", + "flat_roof_covering", + "rainwater_goods", + "loft_insulation", + "porch_canopy", + "chimney", + "fascia", + "soffit", + "fascia_soffit_bargeboards", + "gutters", + "store_roof", + "garage_roof", + "garage_and_store_roof", + "external_wall", + "external_noise_insulation", + "primary_wall", + "secondary_wall", + "downpipes", + "external_decoration", + "cladding", + "spandrel_panels", + "garage_walls", + "party_wall_fire_break", + "external_brickwork_pointing", + "internal_downpipes_external_area", + "external_windows", + "communal_windows", + "secondary_glazing", + "store_windows", + "garage_windows", + "garage_and_store_windows", + "external_door", + "front_door", + "rear_door", + "store_door", + "garage_door", + "garage_and_store_door", + "communal_entrance_door", + "main_door", + "block_entrance_door", + "lintel", + "patio_french_door", + "door_entry_handset", + "paths_and_hardstandings", + "parking_areas", + "boundary_walls", + "front_fencing", + "rear_fencing", + "side_fencing", + "rear_gate", + "front_gate", + "gates", + "retaining_walls", + "private_balcony", + "balcony_balustrade", + "outbuildings", + "garage_structure", + "paving", + "roads", + "soil_and_vent", + "solar_thermals", + "drop_kerb", + "outbuilding_overhaul", + "external_structural_defects", + "access_ramp", + "kitchen", + "kitchen_space_layout", + "tenant_installed_kitchen", + "kitchen_extractor_fan", + "bathroom", + "secondary_bathroom", + "secondary_toilet", + "bathroom_extractor_fan", + "additional_wc_or_whb", + "bathroom_remaining_life_source", + "kitchen_remaining_life_source", + "central_heating", + "heating_boiler", + "heating_distribution", + "secondary_heating", + "hot_water_system", + "cold_water_storage", + "heating_system", + "boiler_fuel", + "water_heating", + "programmable_heating", + "community_heating", + "gas_available", + "heat_recovery_units", + "heating_improvements", + "electrical_wiring", + "consumer_unit", + "smoke_detection", + "heat_detection", + "carbon_monoxide_detection", + "fire_door_rating", + "fire_risk_assessment", + "internal_wiring", + "electrics", + "communal_heating", + "communal_boiler", + "communal_electrics", + "communal_fire_alarm", + "communal_emergency_lighting", + "communal_door_entry", + "communal_cctv", + "communal_bin_store", + "communal_bin_store_doors", + "communal_bin_store_walls", + "communal_bin_store_roof", + "communal_refuse_chute", + "communal_floor_covering", + "communal_kitchen", + "communal_bathroom", + "communal_toilets", + "communal_gates", + "communal_lift", + "communal_passenger_lift", + "communal_balcony_walkway", + "communal_entrance", + "communal_internal_decorations", + "communal_internal_floor", + "communal_walkways", + "communal_external_doors", + "communal_stairs", + "communal_aerial", + "communal_aov", + "communal_internal_doors", + "communal_lateral_mains", + "communal_lighting", + "communal_lighting_conductor", + "communal_store_roof", + "communal_store_walls", + "communal_store_doors", + "communal_warden_call_system", + "communal_bms", + "communal_booster_pump", + "communal_dry_riser", + "communal_wet_riser", + "communal_cold_water_storage", + "communal_sprinkler", + "communal_plug_sockets", + "communal_circulation_space", + "ffhh_damp", + "ffhh_hold_and_cold_water", + "ffhh_drainage_lavatories", + "ffhh_neglected", + "ffhh_natural_light", + "ffhh_ventilation", + "ffhh_food_prep_and_washup", + "ffhh_unsafe_layout", + "ffhh_unstable_building", + "hhsrs_damp_and_mould", + "hhsrs_excess_cold", + "hhsrs_excess_heat", + "hhsrs_asbestos_and_mmf", + "hhsrs_biocides", + "hhsrs_carbon_monoxide", + "hhsrs_lead", + "hhsrs_radiation", + "hhsrs_uncombusted_fuel_gas", + "hhsrs_volatile_organic_compounds", + "hhsrs_crowding_and_space", + "hhsrs_entry_by_intruders", + "hhsrs_lighting", + "hhsrs_noise", + "hhsrs_domestic_hygiene_pests_refuse", + "hhsrs_food_safety", + "hhsrs_personal_hygiene_sanitation", + "hhsrs_water_supply", + "hhsrs_falls_associated_with_baths", + "hhsrs_falls_on_level_surfaces", + "hhsrs_falls_on_stairs", + "hhsrs_falls_between_levels", + "hhsrs_electrical_hazards", + "hhsrs_fire", + "hhsrs_flames_hot_surfaces", + "hhsrs_collision_and_entrapment", + "hhsrs_collision_hazards_low_headroom", + "hhsrs_explosions", + "hhsrs_ergonomics", + "hhsrs_structural_collapse", + "hhsrs_amenities" + ] + }, + "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.inspection_archetype_2": { + "name": "inspection_archetype_2", + "schema": "public", + "values": [ + "detached", + "mid-terrace", + "enclosed mid-terrace", + "end-terrace", + "enclosed end-terrace", + "semi-detached" + ] + }, + "public.inspection_archetype": { + "name": "inspection_archetype", + "schema": "public", + "values": [ + "Bungalow", + "Flat", + "Maisonette", + "House", + "non-domestic" + ] + }, + "public.inspection_borescoped": { + "name": "inspection_borescoped", + "schema": "public", + "values": [ + "yes", + "no", + "refused" + ] + }, + "public.inspections_access_issues": { + "name": "inspections_access_issues", + "schema": "public", + "values": [ + "see notes", + "damp issues", + "foliage on walls", + "bushes against wall", + "trees around/anove property", + "high rise block flats/maisonettes", + "conservatory", + "lean-to", + "garage", + "extension", + "decking", + "shed against wall" + ] + }, + "public.inspections_cladding": { + "name": "inspections_cladding", + "schema": "public", + "values": [ + "none", + "cladded with “sufficient space to fill the wall”", + "cladded with “insufficient space to fill the wall”" + ] + }, + "public.inspections_insulation_material": { + "name": "inspections_insulation_material", + "schema": "public", + "values": [ + "empty 50-90", + "empty 100+", + "empty 30-40", + "empty less than 30", + "loose fibre/wool", + "eps/celo/king", + "fibre batts - with cavity", + "fibre batts - no cavity", + "loose bead", + "glued bead", + "formaldehyde", + "bubble wrap", + "poly chunks" + ] + }, + "public.inspections_rendered": { + "name": "inspections_rendered", + "schema": "public", + "values": [ + "no render", + "rendered with “insufficient” space between dpc and render", + "rendered with “sufficient” space between dpc and render" + ] + }, + "public.inspections_roof_orientation": { + "name": "inspections_roof_orientation", + "schema": "public", + "values": [ + "north", + "east", + "south", + "west", + "north-east", + "north-west", + "south-east", + "south-west", + "n/s split", + "e/w split", + "ne/sw split", + "nw/se split", + "flat roof", + "no roof", + "roof too small", + "already has solar pv" + ] + }, + "public.inspections_tile_hung": { + "name": "inspections_tile_hung", + "schema": "public", + "values": [ + "yes", + "no", + "first floor flats are tile hung" + ] + }, + "public.inspections_wall_construction": { + "name": "inspections_wall_construction", + "schema": "public", + "values": [ + "cavity", + "solid", + "system built", + "timber framed", + "steel framed", + "re-walled cavity", + "mansard pre-fab", + "mansard ewi", + "mansard re-walled" + ] + }, + "public.inspections_wall_insulation": { + "name": "inspections_wall_insulation", + "schema": "public", + "values": [ + "empty cavity", + "filled at build", + "partial", + "retro drilled", + "ewi", + "iwi", + "solid non-cavity", + "system built", + "timber framed", + "steel framed" + ] + }, + "public.built_form_type": { + "name": "built_form_type", + "schema": "public", + "values": [ + "Detached", + "Semi-Detached", + "Mid-Terrace", + "End-Terrace", + "Enclosed Mid-Terrace", + "Enclosed End-Terrace", + "Not Recorded", + "Unknown" + ] + }, + "public.construction_age_band": { + "name": "construction_age_band", + "schema": "public", + "values": [ + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "Unknown" + ] + }, + "public.glazing": { + "name": "glazing", + "schema": "public", + "values": [ + "Single glazing", + "Double glazing, 2002 or later", + "Double glazing, pre-2002", + "Triple glazing, pre-2002", + "Triple glazing, 2002 or later", + "Mixed glazing", + "Secondary glazing", + "Unknown" + ] + }, + "public.main_fuel": { + "name": "main_fuel", + "schema": "public", + "values": [ + "mains gas", + "mains gas (community)", + "electricity", + "electricity (community)", + "LPG (bulk)", + "bottled LPG", + "LPG special condition", + "oil", + "house coal", + "smokeless coal", + "dual fuel (mineral and wood)", + "biomass (community)", + "wood logs", + "Unknown" + ] + }, + "public.main_heating_system": { + "name": "main_heating_system", + "schema": "public", + "values": [ + "Gas boiler, combi", + "Gas boiler, regular", + "Gas CPSU", + "Electric storage heaters, old", + "Electric storage heaters, slimline", + "Electric storage heaters, convector", + "Electric storage heaters, fan", + "Direct-acting electric", + "Electric room heaters", + "Solid fuel room heater, closed", + "Air source heat pump", + "Community heating, boilers", + "Community heating, CHP and boilers", + "Oil room heater, 2000 or later", + "Gas room heater, condensing fire", + "Gas room heater, decorative fuel-effect", + "Gas room heater, flush live-effect", + "Gas room heater, open flue 1980 or later", + "Gas room heater, open flue pre-1980", + "Electric storage heaters, high heat retention", + "Solid fuel room heater, open fire", + "Solid fuel room heater, open fire with back boiler", + "Solid fuel room heater, closed with boiler", + "Electric boiler", + "Electric CPSU", + "Electric underfloor, in concrete slab (off-peak)", + "Electric underfloor, integrated storage and direct-acting", + "Electric underfloor, in screed above insulation", + "Unknown" + ] + }, + "public.override_source": { + "name": "override_source", + "schema": "public", + "values": [ + "classifier", + "user", + "os_places" + ] + }, + "public.property_type": { + "name": "property_type", + "schema": "public", + "values": [ + "House", + "Bungalow", + "Flat", + "Maisonette", + "Park home", + "Unknown" + ] + }, + "public.roof_type": { + "name": "roof_type", + "schema": "public", + "values": [ + "Flat, insulated", + "Flat, insulated (assumed)", + "Flat, limited insulation", + "Flat, limited insulation (assumed)", + "Flat, no insulation", + "Flat, no insulation (assumed)", + "Flat, 12 mm insulation", + "Flat, 25 mm insulation", + "Flat, 50 mm insulation", + "Flat, 75 mm insulation", + "Flat, 100 mm insulation", + "Flat, 125 mm insulation", + "Flat, 150 mm insulation", + "Flat, 175 mm insulation", + "Flat, 200 mm insulation", + "Flat, 225 mm insulation", + "Flat, 250 mm insulation", + "Flat, 270 mm insulation", + "Flat, 300 mm insulation", + "Flat, 350 mm insulation", + "Flat, 400 mm insulation", + "Flat, 400+ mm insulation", + "Pitched, insulated", + "Pitched, insulated (assumed)", + "Pitched, insulated at rafters", + "Pitched, limited insulation", + "Pitched, limited insulation (assumed)", + "Pitched, no insulation", + "Pitched, no insulation (assumed)", + "Pitched, Unknown loft insulation", + "Pitched, 0 mm loft insulation", + "Pitched, 12 mm loft insulation", + "Pitched, 25 mm loft insulation", + "Pitched, 50 mm loft insulation", + "Pitched, 75 mm loft insulation", + "Pitched, 100 mm loft insulation", + "Pitched, 125 mm loft insulation", + "Pitched, 150 mm loft insulation", + "Pitched, 175 mm loft insulation", + "Pitched, 200 mm loft insulation", + "Pitched, 225 mm loft insulation", + "Pitched, 250 mm loft insulation", + "Pitched, 270 mm loft insulation", + "Pitched, 300 mm loft insulation", + "Pitched, 350 mm loft insulation", + "Pitched, 400 mm loft insulation", + "Pitched, 400+ mm loft insulation", + "Roof room(s), insulated", + "Roof room(s), insulated (assumed)", + "Roof room(s), limited insulation", + "Roof room(s), limited insulation (assumed)", + "Roof room(s), no insulation", + "Roof room(s), no insulation (assumed)", + "Roof room(s), ceiling insulated", + "Roof room(s), thatched", + "Roof room(s), thatched with additional insulation", + "Thatched", + "Thatched, with additional insulation", + "(another dwelling above)", + "(same dwelling above)", + "(other premises above)", + "(another premises above)", + "Another Premises Above", + "Unknown" + ] + }, + "public.wall_type": { + "name": "wall_type", + "schema": "public", + "values": [ + "Cavity wall, filled cavity", + "Cavity wall, as built, insulated (assumed)", + "Cavity wall, as built, no insulation (assumed)", + "Cavity wall, as built, partial insulation (assumed)", + "Cavity wall, with internal insulation", + "Cavity wall, with external insulation", + "Cavity wall, filled cavity and internal insulation", + "Cavity wall, filled cavity and external insulation", + "Solid brick, as built, no insulation (assumed)", + "Solid brick, as built, insulated (assumed)", + "Solid brick, as built, partial insulation (assumed)", + "Solid brick, with internal insulation", + "Solid brick, with external insulation", + "Timber frame, as built, no insulation (assumed)", + "Timber frame, as built, insulated (assumed)", + "Timber frame, as built, partial insulation (assumed)", + "Timber frame, with additional insulation", + "Sandstone, as built, no insulation (assumed)", + "Sandstone, as built, insulated (assumed)", + "Sandstone, as built, partial insulation (assumed)", + "Sandstone, with internal insulation", + "Sandstone, with external insulation", + "Granite or whin, as built, no insulation (assumed)", + "Granite or whin, as built, insulated (assumed)", + "Granite or whin, as built, partial insulation (assumed)", + "Granite or whin, with internal insulation", + "Granite or whin, with external insulation", + "System built, as built, no insulation (assumed)", + "System built, as built, insulated (assumed)", + "System built, as built, partial insulation (assumed)", + "System built, with internal insulation", + "System built, with external insulation", + "Park home wall, as built", + "Park home wall, with internal insulation", + "Park home wall, with external insulation", + "Cob, as built", + "Cob, with internal insulation", + "Cob, with external insulation", + "Curtain wall", + "Curtain Wall, as built, no insulation (assumed)", + "Curtain Wall, as built, insulated (assumed)", + "Curtain Wall, filled cavity", + "Curtain Wall, with internal insulation", + "Basement wall", + "Basement wall, as built", + "Unknown" + ] + }, + "public.water_heating": { + "name": "water_heating", + "schema": "public", + "values": [ + "From main system, mains gas", + "From main system, electricity", + "From main system, oil", + "From main system, LPG (bulk)", + "From main system, bottled LPG", + "From main system, house coal", + "Electric immersion, electricity", + "Gas boiler/circulator, mains gas", + "From main system, wood logs", + "From main system, biomass (community)", + "From main system, dual fuel (mineral and wood)", + "From main system, biodiesel (community)", + "Unknown" + ] + }, + "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", + "secondary_glazing", + "double_glazing", + "trickle_vent", + "door_undercut", + "solar_pv", + "solar_battery", + "scaffolding", + "high_heat_retention_storage_heaters", + "air_source_heat_pump", + "boiler_upgrade", + "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.portfolio_capability": { + "name": "portfolio_capability", + "schema": "public", + "values": [ + "approver", + "contractor" + ] + }, + "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.override_component": { + "name": "override_component", + "schema": "public", + "values": [ + "wall_type", + "roof_type", + "property_type", + "built_form_type", + "main_fuel", + "glazing", + "construction_age_band", + "water_heating", + "main_heating_system" + ] + }, + "public.energy_element_type": { + "name": "energy_element_type", + "schema": "public", + "values": [ + "roof", + "wall", + "floor", + "main_heating", + "window", + "lighting", + "hot_water", + "secondary_heating", + "main_heating_controls" + ] + }, + "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.rebaseline_reason": { + "name": "rebaseline_reason", + "schema": "public", + "values": [ + "none", + "pre_sap10", + "physical_state_changed", + "both" + ] + }, + "public.housing_type": { + "name": "housing_type", + "schema": "public", + "values": [ + "Private", + "Social" + ] + }, + "public.measure_type": { + "name": "measure_type", + "schema": "public", + "values": [ + "air_source_heat_pump", + "boiler_upgrade", + "high_heat_retention_storage_heaters", + "secondary_heating", + "roomstat_programmer_trvs", + "time_temperature_zone_control", + "cylinder_thermostat", + "cavity_wall_insulation", + "extension_cavity_wall_insulation", + "external_wall_insulation", + "internal_wall_insulation", + "loft_insulation", + "flat_roof_insulation", + "room_roof_insulation", + "solid_floor_insulation", + "suspended_floor_insulation", + "double_glazing", + "secondary_glazing", + "draught_proofing", + "mechanical_ventilation", + "low_energy_lighting", + "solar_pv", + "hot_water_tank_insulation", + "sealing_open_fireplace" + ] + }, + "public.plan_type": { + "name": "plan_type", + "schema": "public", + "values": [ + "solar_eco4", + "solar_hhrsh_eco4", + "empty_cavity_eco", + "partial_cavity_eco", + "extraction_eco" + ] + }, + "public.unit_quantity": { + "name": "unit_quantity", + "schema": "public", + "values": [ + "m2", + "part", + "kwp" + ] + }, + "public.scenario_type": { + "name": "scenario_type", + "schema": "public", + "values": [ + "unit", + "building" + ] + }, + "public.source": { + "name": "source", + "schema": "public", + "values": [ + "portfolio_id", + "hubspot_deal_id", + "property_id" + ] + }, + "public.file_source": { + "name": "file_source", + "schema": "public", + "values": [ + "pas hub", + "sharepoint", + "hubspot", + "ecmk", + "contractor", + "magic_plan", + "coordination_hub", + "audit_generator", + "projects" + ] + }, + "public.file_type": { + "name": "file_type", + "schema": "public", + "values": [ + "photo_pack", + "site_note", + "rd_sap_site_note", + "pas_2023_ventilation", + "pas_2023_condition", + "pas_significance", + "par_photo_pack", + "pas_2023_property", + "pas_2023_occupancy", + "ecmk_site_note", + "ecmk_rd_sap_site_note", + "ecmk_survey_xml", + "pre_photo", + "mid_photo", + "post_photo", + "loft_hatch_photo", + "dmev_photos", + "door_undercut_photos", + "trickle_vent_photos", + "pre_installation_building_inspection", + "point_of_work_risk_assessment", + "claim_of_compliance", + "mcs_compliance_certificate", + "certificate_of_conformity", + "minor_works_electrical_certificate", + "trustmark_licence_numbers", + "operative_competency", + "ventilation_assessment_checklist", + "anemometer_readings", + "commissioning_records", + "part_f_ventilation_document", + "handover_pack", + "insurance_guarantee", + "workmanship_warranty", + "g98_notification", + "installer_qualifications", + "installer_feedback", + "contractor_other", + "magic_plan_json", + "improvement_option_evaluation", + "medium_term_improvement_plan", + "retrofit_design_doc", + "ventilation_audit", + "other" + ] + }, + "public.user_defined_deal_measure_source": { + "name": "user_defined_deal_measure_source", + "schema": "public", + "values": [ + "instructed", + "pibi_ordered" + ] + }, + "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/0278_snapshot.json b/src/app/db/migrations/meta/0278_snapshot.json new file mode 100644 index 00000000..ddea7ba5 --- /dev/null +++ b/src/app/db/migrations/meta/0278_snapshot.json @@ -0,0 +1,13489 @@ +{ + "id": "587523ce-86b8-4329-b215-5ead69a0e951", + "prevId": "43985c13-e221-4ced-b131-844eefb2330b", + "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()" + }, + "last_updated_at": { + "name": "last_updated_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.deal_measure_approval_events": { + "name": "deal_measure_approval_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "acted_by": { + "name": "acted_by", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "acted_at": { + "name": "acted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_deal_measure_events_deal_id": { + "name": "idx_deal_measure_events_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_deal_measure_events_acted_at": { + "name": "idx_deal_measure_events_acted_at", + "columns": [ + { + "expression": "acted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deal_measure_approval_events_acted_by_user_id_fk": { + "name": "deal_measure_approval_events_acted_by_user_id_fk", + "tableFrom": "deal_measure_approval_events", + "tableTo": "user", + "columnsFrom": [ + "acted_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deal_measure_approvals": { + "name": "deal_measure_approvals", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_approved": { + "name": "is_approved", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "approved_by": { + "name": "approved_by", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "approved_at": { + "name": "approved_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_deal_measure_approvals_deal_id": { + "name": "idx_deal_measure_approvals_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deal_measure_approvals_approved_by_user_id_fk": { + "name": "deal_measure_approvals_approved_by_user_id_fk", + "tableFrom": "deal_measure_approvals", + "tableTo": "user", + "columnsFrom": [ + "approved_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "uq_deal_measure": { + "name": "uq_deal_measure", + "nullsNotDistinct": false, + "columns": [ + "hubspot_deal_id", + "measure_name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bulk_address_uploads": { + "name": "bulk_address_uploads", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "s3_bucket": { + "name": "s3_bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "s3_key": { + "name": "s3_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "filename": { + "name": "filename", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'ready_for_processing'" + }, + "source_headers": { + "name": "source_headers", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "column_mapping": { + "name": "column_mapping", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "multi_entry_summary": { + "name": "multi_entry_summary", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "multi_entry_ordering": { + "name": "multi_entry_ordering", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "verify_ack": { + "name": "verify_ack", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "task_id": { + "name": "task_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "combined_output_s3_uri": { + "name": "combined_output_s3_uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bulk_upload_uprn_corrections": { + "name": "bulk_upload_uprn_corrections", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "upload_id": { + "name": "upload_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "source_row_id": { + "name": "source_row_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address": { + "name": "address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "marked_no_uprn": { + "name": "marked_no_uprn", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "bulk_upload_uprn_corrections_upload_id_bulk_address_uploads_id_fk": { + "name": "bulk_upload_uprn_corrections_upload_id_bulk_address_uploads_id_fk", + "tableFrom": "bulk_upload_uprn_corrections", + "tableTo": "bulk_address_uploads", + "columnsFrom": [ + "upload_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "bulk_upload_uprn_corrections_upload_row_unique": { + "name": "bulk_upload_uprn_corrections_upload_row_unique", + "nullsNotDistinct": false, + "columns": [ + "upload_id", + "source_row_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.aspect_condition": { + "name": "aspect_condition", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "element_id": { + "name": "element_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "aspect_type": { + "name": "aspect_type", + "type": "aspect_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "aspect_instance": { + "name": "aspect_instance", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "quantity": { + "name": "quantity", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "install_date": { + "name": "install_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "renewal_year": { + "name": "renewal_year", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "comments": { + "name": "comments", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "aspect_condition_element_id_element_id_fk": { + "name": "aspect_condition_element_id_element_id_fk", + "tableFrom": "aspect_condition", + "tableTo": "element", + "columnsFrom": [ + "element_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.element": { + "name": "element", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "survey_id": { + "name": "survey_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "element_type": { + "name": "element_type", + "type": "element_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "element_instance": { + "name": "element_instance", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "element_survey_id_property_condition_survey_id_fk": { + "name": "element_survey_id_property_condition_survey_id_fk", + "tableFrom": "element", + "tableTo": "property_condition_survey", + "columnsFrom": [ + "survey_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_condition_survey": { + "name": "property_condition_survey", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "date": { + "name": "date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hubspot_company_data": { + "name": "hubspot_company_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "company_name": { + "name": "company_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "group_id": { + "name": "group_id", + "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": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hubspot_deal_data": { + "name": "hubspot_deal_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "deal_id": { + "name": "deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dealname": { + "name": "dealname", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dealstage": { + "name": "dealstage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "company_id": { + "name": "company_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "project_code": { + "name": "project_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "landlord_property_id": { + "name": "landlord_property_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "listing_id": { + "name": "listing_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uprn": { + "name": "uprn", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "outcome": { + "name": "outcome", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "outcome_notes": { + "name": "outcome_notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "major_condition_issue_description": { + "name": "major_condition_issue_description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "major_condition_issue_photos": { + "name": "major_condition_issue_photos", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "major_condition_issue_evidence_s3_url": { + "name": "major_condition_issue_evidence_s3_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "coordination_status": { + "name": "coordination_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "design_status": { + "name": "design_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "booking_status": { + "name": "booking_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pashub_link": { + "name": "pashub_link", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sharepoint_link": { + "name": "sharepoint_link", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dampmould_growth": { + "name": "dampmould_growth", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pre_sap": { + "name": "pre_sap", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "coordinator": { + "name": "coordinator", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mtp_completion_date": { + "name": "mtp_completion_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "mtp_re_model_completion_date": { + "name": "mtp_re_model_completion_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "ioe_v3_completion_date": { + "name": "ioe_v3_completion_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "proposed_measures": { + "name": "proposed_measures", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "approved_package": { + "name": "approved_package", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "designer": { + "name": "designer", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "design_type": { + "name": "design_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "design_completion_date": { + "name": "design_completion_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "actual_measures_installed": { + "name": "actual_measures_installed", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "installer": { + "name": "installer", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "installer_handover": { + "name": "installer_handover", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lodgement_status": { + "name": "lodgement_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "measures_lodgement_date": { + "name": "measures_lodgement_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "lodgement_date": { + "name": "lodgement_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "expected_commencement_date": { + "name": "expected_commencement_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "coordination_comments": { + "name": "coordination_comments", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "surveyor": { + "name": "surveyor", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "damp_mould_and_repairs_comments": { + "name": "damp_mould_and_repairs_comments", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "batch": { + "name": "batch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "batch_description": { + "name": "batch_description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "block_reference": { + "name": "block_reference", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "nonfunded_measures": { + "name": "nonfunded_measures", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_prn": { + "name": "epc_prn", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "potential_post_sap_score_dropdown": { + "name": "potential_post_sap_score_dropdown", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ei_score": { + "name": "ei_score", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ei_score__potential_": { + "name": "ei_score__potential_", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_sap_score": { + "name": "epc_sap_score", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_sap_score__potential_": { + "name": "epc_sap_score__potential_", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmed_survey_date": { + "name": "confirmed_survey_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "confirmed_survey_time": { + "name": "confirmed_survey_time", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "surveyed_date": { + "name": "surveyed_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "survey_type": { + "name": "survey_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "measures_for_pibi_ordered": { + "name": "measures_for_pibi_ordered", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pibi_order_date": { + "name": "pibi_order_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "pibi_completed_date": { + "name": "pibi_completed_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "property_halted_date": { + "name": "property_halted_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "property_halted_reason": { + "name": "property_halted_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "technical_approved_measures_for_install": { + "name": "technical_approved_measures_for_install", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sent_to_installer_for_pricing": { + "name": "sent_to_installer_for_pricing", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "domna_survey_required": { + "name": "domna_survey_required", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "domna_survey_type": { + "name": "domna_survey_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "domna_survey_date": { + "name": "domna_survey_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "date_booking_made": { + "name": "date_booking_made", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "last_contact_date": { + "name": "last_contact_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "last_outbound_call": { + "name": "last_outbound_call", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "last_outbound_email": { + "name": "last_outbound_email", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "last_submission_date": { + "name": "last_submission_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "number_of_attempts": { + "name": "number_of_attempts", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "client_booking_reference": { + "name": "client_booking_reference", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "third_party_surveyor_identifier": { + "name": "third_party_surveyor_identifier", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "design_constraints": { + "name": "design_constraints", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "planning_comments": { + "name": "planning_comments", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "planning_status": { + "name": "planning_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "planning_suggested_approach": { + "name": "planning_suggested_approach", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "planning_authority": { + "name": "planning_authority", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "designated_area": { + "name": "designated_area", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "article_4_pd_rights": { + "name": "article_4_pd_rights", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "listed_building": { + "name": "listed_building", + "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": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hubspot_projects_data": { + "name": "hubspot_projects_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "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": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "hubspot_projects_data_project_id_unique": { + "name": "hubspot_projects_data_project_id_unique", + "nullsNotDistinct": false, + "columns": [ + "project_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hubspot_users": { + "name": "hubspot_users", + "schema": "", + "columns": { + "hubspot_owner_id": { + "name": "hubspot_owner_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "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.epc_store": { + "name": "epc_store", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "epc_api_created_at": { + "name": "epc_api_created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "epc_api": { + "name": "epc_api", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "epc_page_created_at": { + "name": "epc_page_created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "epc_page": { + "name": "epc_page", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_page_rrn": { + "name": "epc_page_rrn", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "uq_epc_store_uprn": { + "name": "uq_epc_store_uprn", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.files_from_surveyor": { + "name": "files_from_surveyor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "s3_json_url": { + "name": "s3_json_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "files_from_surveyor_portfolio_id_portfolio_id_fk": { + "name": "files_from_surveyor_portfolio_id_portfolio_id_fk", + "tableFrom": "files_from_surveyor", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "files_from_surveyor_property_id_property_id_fk": { + "name": "files_from_surveyor_property_id_property_id_fk", + "tableFrom": "files_from_surveyor", + "tableTo": "property", + "columnsFrom": [ + "property_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.inspections": { + "name": "inspections", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "archetype": { + "name": "archetype", + "type": "inspection_archetype", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "archetype_2": { + "name": "archetype_2", + "type": "inspection_archetype_2", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "wall_construction": { + "name": "wall_construction", + "type": "inspections_wall_construction", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "insulation": { + "name": "insulation", + "type": "inspections_wall_insulation", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "insulation_material": { + "name": "insulation_material", + "type": "inspections_insulation_material", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "borescoped": { + "name": "borescoped", + "type": "inspection_borescoped", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "roof_orientation": { + "name": "roof_orientation", + "type": "inspections_roof_orientation", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "tile_hung": { + "name": "tile_hung", + "type": "inspections_tile_hung", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "rendered": { + "name": "rendered", + "type": "inspections_rendered", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "cladding": { + "name": "cladding", + "type": "inspections_cladding", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "access_issues": { + "name": "access_issues", + "type": "inspections_access_issues", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "surveyor_name": { + "name": "surveyor_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "inspections_property_id_property_id_fk": { + "name": "inspections_property_id_property_id_fk", + "tableFrom": "inspections", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_built_form_type_overrides": { + "name": "landlord_built_form_type_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "built_form_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_built_form_type_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_built_form_type_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_built_form_type_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_built_form_type_overrides_portfolio_description_unique": { + "name": "landlord_built_form_type_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_construction_age_band_overrides": { + "name": "landlord_construction_age_band_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "construction_age_band", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_construction_age_band_overrides_portfolio_fk": { + "name": "landlord_construction_age_band_overrides_portfolio_fk", + "tableFrom": "landlord_construction_age_band_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_construction_age_band_portfolio_description_unique": { + "name": "landlord_construction_age_band_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_glazing_overrides": { + "name": "landlord_glazing_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "glazing", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_glazing_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_glazing_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_glazing_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_glazing_overrides_portfolio_description_unique": { + "name": "landlord_glazing_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_main_fuel_overrides": { + "name": "landlord_main_fuel_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "main_fuel", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_main_fuel_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_main_fuel_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_main_fuel_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_main_fuel_overrides_portfolio_description_unique": { + "name": "landlord_main_fuel_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_main_heating_system_overrides": { + "name": "landlord_main_heating_system_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "main_heating_system", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_main_heating_system_overrides_portfolio_fk": { + "name": "landlord_main_heating_system_overrides_portfolio_fk", + "tableFrom": "landlord_main_heating_system_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_main_heating_system_portfolio_description_unique": { + "name": "landlord_main_heating_system_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_property_type_overrides": { + "name": "landlord_property_type_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "property_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_property_type_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_property_type_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_property_type_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_property_type_overrides_portfolio_description_unique": { + "name": "landlord_property_type_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_roof_type_overrides": { + "name": "landlord_roof_type_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "roof_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_roof_type_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_roof_type_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_roof_type_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_roof_type_overrides_portfolio_description_unique": { + "name": "landlord_roof_type_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_wall_type_overrides": { + "name": "landlord_wall_type_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "wall_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_wall_type_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_wall_type_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_wall_type_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_wall_type_overrides_portfolio_description_unique": { + "name": "landlord_wall_type_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_water_heating_overrides": { + "name": "landlord_water_heating_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "water_heating", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_water_heating_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_water_heating_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_water_heating_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_water_heating_overrides_portfolio_description_unique": { + "name": "landlord_water_heating_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_door_ventilation": { + "name": "magic_plan_door_ventilation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_door_id": { + "name": "magic_plan_door_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "undercut_mm": { + "name": "undercut_mm", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_door_ventilation_magic_plan_door_id_magic_plan_door_id_fk": { + "name": "magic_plan_door_ventilation_magic_plan_door_id_magic_plan_door_id_fk", + "tableFrom": "magic_plan_door_ventilation", + "tableTo": "magic_plan_door", + "columnsFrom": [ + "magic_plan_door_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "magic_plan_door_ventilation_magic_plan_door_id_unique": { + "name": "magic_plan_door_ventilation_magic_plan_door_id_unique", + "nullsNotDistinct": false, + "columns": [ + "magic_plan_door_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_door": { + "name": "magic_plan_door", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_room_id": { + "name": "magic_plan_room_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "width_mm": { + "name": "width_mm", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "height_mm": { + "name": "height_mm", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_door_magic_plan_room_id_magic_plan_room_id_fk": { + "name": "magic_plan_door_magic_plan_room_id_magic_plan_room_id_fk", + "tableFrom": "magic_plan_door", + "tableTo": "magic_plan_room", + "columnsFrom": [ + "magic_plan_room_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_floor": { + "name": "magic_plan_floor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_plan_id": { + "name": "magic_plan_plan_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "level": { + "name": "level", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_floor_magic_plan_plan_id_magic_plan_plan_id_fk": { + "name": "magic_plan_floor_magic_plan_plan_id_magic_plan_plan_id_fk", + "tableFrom": "magic_plan_floor", + "tableTo": "magic_plan_plan", + "columnsFrom": [ + "magic_plan_plan_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_plan": { + "name": "magic_plan_plan", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address": { + "name": "address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "magic_plan_uid": { + "name": "magic_plan_uid", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uploaded_file_id": { + "name": "uploaded_file_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_plan_uploaded_file_id_uploaded_files_id_fk": { + "name": "magic_plan_plan_uploaded_file_id_uploaded_files_id_fk", + "tableFrom": "magic_plan_plan", + "tableTo": "uploaded_files", + "columnsFrom": [ + "uploaded_file_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "magic_plan_plan_magic_plan_uid_unique": { + "name": "magic_plan_plan_magic_plan_uid_unique", + "nullsNotDistinct": false, + "columns": [ + "magic_plan_uid" + ] + }, + "magic_plan_plan_uploaded_file_id_unique": { + "name": "magic_plan_plan_uploaded_file_id_unique", + "nullsNotDistinct": false, + "columns": [ + "uploaded_file_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_room": { + "name": "magic_plan_room", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_floor_id": { + "name": "magic_plan_floor_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "width_m": { + "name": "width_m", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "length_m": { + "name": "length_m", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "area_m2": { + "name": "area_m2", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_room_magic_plan_floor_id_magic_plan_floor_id_fk": { + "name": "magic_plan_room_magic_plan_floor_id_magic_plan_floor_id_fk", + "tableFrom": "magic_plan_room", + "tableTo": "magic_plan_floor", + "columnsFrom": [ + "magic_plan_floor_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_window_ventilation": { + "name": "magic_plan_window_ventilation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_window_id": { + "name": "magic_plan_window_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "opening_type": { + "name": "opening_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "num_openings": { + "name": "num_openings", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "pct_openable": { + "name": "pct_openable", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "trickle_vent_area_mm2": { + "name": "trickle_vent_area_mm2", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "num_trickle_vents": { + "name": "num_trickle_vents", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_window_ventilation_magic_plan_window_id_magic_plan_window_id_fk": { + "name": "magic_plan_window_ventilation_magic_plan_window_id_magic_plan_window_id_fk", + "tableFrom": "magic_plan_window_ventilation", + "tableTo": "magic_plan_window", + "columnsFrom": [ + "magic_plan_window_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "magic_plan_window_ventilation_magic_plan_window_id_unique": { + "name": "magic_plan_window_ventilation_magic_plan_window_id_unique", + "nullsNotDistinct": false, + "columns": [ + "magic_plan_window_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_window": { + "name": "magic_plan_window", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_room_id": { + "name": "magic_plan_room_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "width_m": { + "name": "width_m", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "height_m": { + "name": "height_m", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "area_m2": { + "name": "area_m2", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_window_magic_plan_room_id_magic_plan_room_id_fk": { + "name": "magic_plan_window_magic_plan_room_id_magic_plan_room_id_fk", + "tableFrom": "magic_plan_window", + "tableTo": "magic_plan_room", + "columnsFrom": [ + "magic_plan_room_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": { + "idx_material_active": { + "name": "idx_material_active", + "columns": [ + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"material\".\"is_active\"", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organisation": { + "name": "organisation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "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()" + }, + "hubspot_company_id": { + "name": "hubspot_company_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pibi_requests": { + "name": "pibi_requests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "ordered_at": { + "name": "ordered_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "pushed_at": { + "name": "pushed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_pibi_requests_deal_id": { + "name": "idx_pibi_requests_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_pibi_requests_portfolio_id": { + "name": "idx_pibi_requests_portfolio_id", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pibi_requests_portfolio_id_portfolio_id_fk": { + "name": "pibi_requests_portfolio_id_portfolio_id_fk", + "tableFrom": "pibi_requests", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "pibi_requests_created_by_user_id_user_id_fk": { + "name": "pibi_requests_created_by_user_id_user_id_fk", + "tableFrom": "pibi_requests", + "tableTo": "user", + "columnsFrom": [ + "created_by_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.portfolio_organisation": { + "name": "portfolio_organisation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "organisation_id": { + "name": "organisation_id", + "type": "uuid", + "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": { + "portfolio_organisation_portfolio_id_portfolio_id_fk": { + "name": "portfolio_organisation_portfolio_id_portfolio_id_fk", + "tableFrom": "portfolio_organisation", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "portfolio_organisation_organisation_id_organisation_id_fk": { + "name": "portfolio_organisation_organisation_id_organisation_id_fk", + "tableFrom": "portfolio_organisation", + "tableTo": "organisation", + "columnsFrom": [ + "organisation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "portfolio_organisation_portfolio_id_organisation_id_unique": { + "name": "portfolio_organisation_portfolio_id_organisation_id_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "organisation_id" + ] + } + }, + "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.portfolio_capabilities": { + "name": "portfolio_capabilities", + "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 + }, + "capability": { + "name": "capability", + "type": "portfolio_capability", + "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": { + "portfolio_capabilities_user_id_user_id_fk": { + "name": "portfolio_capabilities_user_id_user_id_fk", + "tableFrom": "portfolio_capabilities", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "portfolio_capabilities_portfolio_id_portfolio_id_fk": { + "name": "portfolio_capabilities_portfolio_id_portfolio_id_fk", + "tableFrom": "portfolio_capabilities", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "portfolio_capabilities_user_id_portfolio_id_capability_unique": { + "name": "portfolio_capabilities_user_id_portfolio_id_capability_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "portfolio_id", + "capability" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.portfolioInvitations": { + "name": "portfolioInvitations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "invited_by_user_id": { + "name": "invited_by_user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "portfolioInvitations_portfolio_id_portfolio_id_fk": { + "name": "portfolioInvitations_portfolio_id_portfolio_id_fk", + "tableFrom": "portfolioInvitations", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "portfolioInvitations_invited_by_user_id_user_id_fk": { + "name": "portfolioInvitations_invited_by_user_id_user_id_fk", + "tableFrom": "portfolioInvitations", + "tableTo": "user", + "columnsFrom": [ + "invited_by_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "portfolio_invitations_portfolio_email_unique": { + "name": "portfolio_invitations_portfolio_email_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "email" + ] + } + }, + "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.project": { + "name": "project", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "organisation_id": { + "name": "organisation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "project_type_id": { + "name": "project_type_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start_date": { + "name": "start_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "end_date": { + "name": "end_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "domna_admin_access": { + "name": "domna_admin_access", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "sharepoint_base_url": { + "name": "sharepoint_base_url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "sharepoint_sub_folder_template": { + "name": "sharepoint_sub_folder_template", + "type": "varchar", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "project_organisation_id_organisation_id_fk": { + "name": "project_organisation_id_organisation_id_fk", + "tableFrom": "project", + "tableTo": "organisation", + "columnsFrom": [ + "organisation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_project_type_id_project_type_id_fk": { + "name": "project_project_type_id_project_type_id_fk", + "tableFrom": "project", + "tableTo": "project_type", + "columnsFrom": [ + "project_type_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_property": { + "name": "project_property", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "project_property_project_id_project_id_fk": { + "name": "project_property_project_id_project_id_fk", + "tableFrom": "project_property", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_property_property_id_property_id_fk": { + "name": "project_property_property_id_property_id_fk", + "tableFrom": "project_property", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "project_property_project_id_property_id_unique": { + "name": "project_property_project_id_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "project_id", + "property_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_type": { + "name": "project_type", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_workstream": { + "name": "project_workstream", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "workstream_id": { + "name": "workstream_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "current_stage_id": { + "name": "current_stage_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "project_workstream_project_id_project_id_fk": { + "name": "project_workstream_project_id_project_id_fk", + "tableFrom": "project_workstream", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_workstream_workstream_id_workstream_id_fk": { + "name": "project_workstream_workstream_id_workstream_id_fk", + "tableFrom": "project_workstream", + "tableTo": "workstream", + "columnsFrom": [ + "workstream_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_workstream_current_stage_id_project_workstream_stage_id_fk": { + "name": "project_workstream_current_stage_id_project_workstream_stage_id_fk", + "tableFrom": "project_workstream", + "tableTo": "project_workstream_stage", + "columnsFrom": [ + "current_stage_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_workstream_contractor": { + "name": "project_workstream_contractor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_workstream_id": { + "name": "project_workstream_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "organisation_id": { + "name": "organisation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "update_stages_permission": { + "name": "update_stages_permission", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "upload_documents_permission": { + "name": "upload_documents_permission", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "assigned_at": { + "name": "assigned_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "project_workstream_contractor_project_workstream_id_project_workstream_id_fk": { + "name": "project_workstream_contractor_project_workstream_id_project_workstream_id_fk", + "tableFrom": "project_workstream_contractor", + "tableTo": "project_workstream", + "columnsFrom": [ + "project_workstream_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_workstream_contractor_organisation_id_organisation_id_fk": { + "name": "project_workstream_contractor_organisation_id_organisation_id_fk", + "tableFrom": "project_workstream_contractor", + "tableTo": "organisation", + "columnsFrom": [ + "organisation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_workstream_evidence_requirement": { + "name": "project_workstream_evidence_requirement", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_workstream_id": { + "name": "project_workstream_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "file_type": { + "name": "file_type", + "type": "file_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "project_workstream_stage_id": { + "name": "project_workstream_stage_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "required": { + "name": "required", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "naming_rule": { + "name": "naming_rule", + "type": "varchar", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "project_workstream_evidence_requirement_project_workstream_id_project_workstream_id_fk": { + "name": "project_workstream_evidence_requirement_project_workstream_id_project_workstream_id_fk", + "tableFrom": "project_workstream_evidence_requirement", + "tableTo": "project_workstream", + "columnsFrom": [ + "project_workstream_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_workstream_evidence_requirement_project_workstream_stage_id_project_workstream_stage_id_fk": { + "name": "project_workstream_evidence_requirement_project_workstream_stage_id_project_workstream_stage_id_fk", + "tableFrom": "project_workstream_evidence_requirement", + "tableTo": "project_workstream_stage", + "columnsFrom": [ + "project_workstream_stage_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_workstream_stage": { + "name": "project_workstream_stage", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_workstream_id": { + "name": "project_workstream_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "start_date": { + "name": "start_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "due_date": { + "name": "due_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "last_updated": { + "name": "last_updated", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status_description": { + "name": "status_description", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "project_workstream_stage_project_workstream_id_project_workstream_id_fk": { + "name": "project_workstream_stage_project_workstream_id_project_workstream_id_fk", + "tableFrom": "project_workstream_stage", + "tableTo": "project_workstream", + "columnsFrom": [ + "project_workstream_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.work_order": { + "name": "work_order", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "reference": { + "name": "reference", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "project_workstream_contractor_id": { + "name": "project_workstream_contractor_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "project_workstream_stage_id": { + "name": "project_workstream_stage_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "forecast_end": { + "name": "forecast_end", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "priority": { + "name": "priority", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "work_order_project_workstream_contractor_id_project_workstream_contractor_id_fk": { + "name": "work_order_project_workstream_contractor_id_project_workstream_contractor_id_fk", + "tableFrom": "work_order", + "tableTo": "project_workstream_contractor", + "columnsFrom": [ + "project_workstream_contractor_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "work_order_property_id_property_id_fk": { + "name": "work_order_property_id_property_id_fk", + "tableFrom": "work_order", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "work_order_project_workstream_stage_id_project_workstream_stage_id_fk": { + "name": "work_order_project_workstream_stage_id_project_workstream_stage_id_fk", + "tableFrom": "work_order", + "tableTo": "project_workstream_stage", + "columnsFrom": [ + "project_workstream_stage_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "work_order_reference_unique": { + "name": "work_order_reference_unique", + "nullsNotDistinct": false, + "columns": [ + "reference" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workstream": { + "name": "workstream", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_overrides": { + "name": "property_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "building_part": { + "name": "building_part", + "type": "smallint", + "primaryKey": false, + "notNull": true + }, + "override_component": { + "name": "override_component", + "type": "override_component", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "override_value": { + "name": "override_value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "original_spreadsheet_description": { + "name": "original_spreadsheet_description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "property_overrides_property_id_property_id_fk": { + "name": "property_overrides_property_id_property_id_fk", + "tableFrom": "property_overrides", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "property_overrides_portfolio_id_portfolio_id_fk": { + "name": "property_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "property_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "property_overrides_property_component_part_unique": { + "name": "property_overrides_property_component_part_unique", + "nullsNotDistinct": false, + "columns": [ + "property_id", + "override_component", + "building_part" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_building_part": { + "name": "epc_building_part", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "construction_age_band": { + "name": "construction_age_band", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "wall_construction": { + "name": "wall_construction", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "wall_insulation_type": { + "name": "wall_insulation_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "wall_thickness_measured": { + "name": "wall_thickness_measured", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "party_wall_construction": { + "name": "party_wall_construction", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "building_part_number": { + "name": "building_part_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "wall_dry_lined": { + "name": "wall_dry_lined", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "wall_thickness_mm": { + "name": "wall_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "wall_insulation_thickness": { + "name": "wall_insulation_thickness", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "wall_insulation_thermal_conductivity": { + "name": "wall_insulation_thermal_conductivity", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "floor_heat_loss": { + "name": "floor_heat_loss", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "floor_insulation_thickness": { + "name": "floor_insulation_thickness", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "flat_roof_insulation_thickness": { + "name": "flat_roof_insulation_thickness", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "floor_type": { + "name": "floor_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "floor_construction_type": { + "name": "floor_construction_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "floor_insulation_type_str": { + "name": "floor_insulation_type_str", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "floor_u_value_known": { + "name": "floor_u_value_known", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "roof_construction": { + "name": "roof_construction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "roof_insulation_location": { + "name": "roof_insulation_location", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "roof_insulation_thickness": { + "name": "roof_insulation_thickness", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "rafter_insulation_thickness": { + "name": "rafter_insulation_thickness", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "roof_construction_type": { + "name": "roof_construction_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "curtain_wall_age": { + "name": "curtain_wall_age", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "wall_is_basement": { + "name": "wall_is_basement", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "wall_u_value": { + "name": "wall_u_value", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_area": { + "name": "alt_wall_1_area", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_dry_lined": { + "name": "alt_wall_1_dry_lined", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_construction": { + "name": "alt_wall_1_construction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_insulation_type": { + "name": "alt_wall_1_insulation_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_thickness_measured": { + "name": "alt_wall_1_thickness_measured", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_insulation_thickness": { + "name": "alt_wall_1_insulation_thickness", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_is_sheltered": { + "name": "alt_wall_1_is_sheltered", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_u_value": { + "name": "alt_wall_1_u_value", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_thickness_mm": { + "name": "alt_wall_1_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_is_basement": { + "name": "alt_wall_1_is_basement", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_area": { + "name": "alt_wall_2_area", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_dry_lined": { + "name": "alt_wall_2_dry_lined", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_construction": { + "name": "alt_wall_2_construction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_insulation_type": { + "name": "alt_wall_2_insulation_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_thickness_measured": { + "name": "alt_wall_2_thickness_measured", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_insulation_thickness": { + "name": "alt_wall_2_insulation_thickness", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_is_sheltered": { + "name": "alt_wall_2_is_sheltered", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_u_value": { + "name": "alt_wall_2_u_value", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_thickness_mm": { + "name": "alt_wall_2_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_is_basement": { + "name": "alt_wall_2_is_basement", + "type": "boolean", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "ix_epc_building_part_epc_property": { + "name": "ix_epc_building_part_epc_property", + "columns": [ + { + "expression": "epc_property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_building_part_epc_property_id_epc_property_id_fk": { + "name": "epc_building_part_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_building_part", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_energy_element": { + "name": "epc_energy_element", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "element_type": { + "name": "element_type", + "type": "energy_element_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "energy_efficiency_rating": { + "name": "energy_efficiency_rating", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "environmental_efficiency_rating": { + "name": "environmental_efficiency_rating", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "ix_epc_energy_element_epc_property": { + "name": "ix_epc_energy_element_epc_property", + "columns": [ + { + "expression": "epc_property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_energy_element_epc_property_id_epc_property_id_fk": { + "name": "epc_energy_element_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_energy_element", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_flat_details": { + "name": "epc_flat_details", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "level": { + "name": "level", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "top_storey": { + "name": "top_storey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "flat_location": { + "name": "flat_location", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "heat_loss_corridor": { + "name": "heat_loss_corridor", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "storey_count": { + "name": "storey_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "unheated_corridor_length_m": { + "name": "unheated_corridor_length_m", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_flat_details_epc_property_id_epc_property_id_fk": { + "name": "epc_flat_details_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_flat_details", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_flat_details_epc_property_id_unique": { + "name": "epc_flat_details_epc_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "epc_property_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_floor_dimension": { + "name": "epc_floor_dimension", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_building_part_id": { + "name": "epc_building_part_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "floor": { + "name": "floor", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "room_height_m": { + "name": "room_height_m", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "total_floor_area_m2": { + "name": "total_floor_area_m2", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "party_wall_length_m": { + "name": "party_wall_length_m", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "heat_loss_perimeter_m": { + "name": "heat_loss_perimeter_m", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "floor_insulation": { + "name": "floor_insulation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "floor_construction": { + "name": "floor_construction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "is_exposed_floor": { + "name": "is_exposed_floor", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_above_partially_heated_space": { + "name": "is_above_partially_heated_space", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "ix_epc_floor_dimension_building_part": { + "name": "ix_epc_floor_dimension_building_part", + "columns": [ + { + "expression": "epc_building_part_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_floor_dimension_epc_building_part_id_epc_building_part_id_fk": { + "name": "epc_floor_dimension_epc_building_part_id_epc_building_part_id_fk", + "tableFrom": "epc_floor_dimension", + "tableTo": "epc_building_part", + "columnsFrom": [ + "epc_building_part_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_main_heating_detail": { + "name": "epc_main_heating_detail", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "has_fghrs": { + "name": "has_fghrs", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "main_fuel_type": { + "name": "main_fuel_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "heat_emitter_type": { + "name": "heat_emitter_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "emitter_temperature": { + "name": "emitter_temperature", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "main_heating_control": { + "name": "main_heating_control", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "fan_flue_present": { + "name": "fan_flue_present", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "boiler_flue_type": { + "name": "boiler_flue_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "boiler_ignition_type": { + "name": "boiler_ignition_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "central_heating_pump_age": { + "name": "central_heating_pump_age", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "central_heating_pump_age_str": { + "name": "central_heating_pump_age_str", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "main_heating_index_number": { + "name": "main_heating_index_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "sap_main_heating_code": { + "name": "sap_main_heating_code", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "main_heating_number": { + "name": "main_heating_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "main_heating_category": { + "name": "main_heating_category", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "main_heating_fraction": { + "name": "main_heating_fraction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "main_heating_data_source": { + "name": "main_heating_data_source", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "condensing": { + "name": "condensing", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "weather_compensator": { + "name": "weather_compensator", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "community_heating_boiler_fuel_type": { + "name": "community_heating_boiler_fuel_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "community_heating_chp_fraction": { + "name": "community_heating_chp_fraction", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "ix_epc_main_heating_detail_epc_property": { + "name": "ix_epc_main_heating_detail_epc_property", + "columns": [ + { + "expression": "epc_property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_main_heating_detail_epc_property_id_epc_property_id_fk": { + "name": "epc_main_heating_detail_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_main_heating_detail", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_photovoltaic_array": { + "name": "epc_photovoltaic_array", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "array_index": { + "name": "array_index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "peak_power": { + "name": "peak_power", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "pitch": { + "name": "pitch", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "overshading": { + "name": "overshading", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "orientation": { + "name": "orientation", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_photovoltaic_array_epc_property_id_epc_property_id_fk": { + "name": "epc_photovoltaic_array_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_photovoltaic_array", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_property": { + "name": "epc_property", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "uploaded_file_id": { + "name": "uploaded_file_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'lodged'" + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "uprn_source": { + "name": "uprn_source", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "report_reference": { + "name": "report_reference", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "report_type": { + "name": "report_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "assessment_type": { + "name": "assessment_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sap_version": { + "name": "sap_version", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "schema_type": { + "name": "schema_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "schema_versions_original": { + "name": "schema_versions_original", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "calculation_software_version": { + "name": "calculation_software_version", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address_line_1": { + "name": "address_line_1", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "address_line_2": { + "name": "address_line_2", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "post_town": { + "name": "post_town", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "region_code": { + "name": "region_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "country_code": { + "name": "country_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "language_code": { + "name": "language_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dwelling_type": { + "name": "dwelling_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "property_type": { + "name": "property_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "built_form": { + "name": "built_form", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tenure": { + "name": "tenure", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "transaction_type": { + "name": "transaction_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "inspection_date": { + "name": "inspection_date", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "completion_date": { + "name": "completion_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "registration_date": { + "name": "registration_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "total_floor_area_m2": { + "name": "total_floor_area_m2", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "measurement_type": { + "name": "measurement_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "solar_water_heating": { + "name": "solar_water_heating", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "has_hot_water_cylinder": { + "name": "has_hot_water_cylinder", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "has_fixed_air_conditioning": { + "name": "has_fixed_air_conditioning", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "has_conservatory": { + "name": "has_conservatory", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "has_heated_separate_conservatory": { + "name": "has_heated_separate_conservatory", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "conservatory_type": { + "name": "conservatory_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "conservatory_floor_area_m2": { + "name": "conservatory_floor_area_m2", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "conservatory_glazed_perimeter_m": { + "name": "conservatory_glazed_perimeter_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "conservatory_double_glazed": { + "name": "conservatory_double_glazed", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "conservatory_thermally_separated": { + "name": "conservatory_thermally_separated", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "conservatory_room_height_storeys": { + "name": "conservatory_room_height_storeys", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "door_count": { + "name": "door_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "wet_rooms_count": { + "name": "wet_rooms_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "extensions_count": { + "name": "extensions_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "heated_rooms_count": { + "name": "heated_rooms_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "open_chimneys_count": { + "name": "open_chimneys_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "habitable_rooms_count": { + "name": "habitable_rooms_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "insulated_door_count": { + "name": "insulated_door_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "cfl_fixed_lighting_bulbs_count": { + "name": "cfl_fixed_lighting_bulbs_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "led_fixed_lighting_bulbs_count": { + "name": "led_fixed_lighting_bulbs_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "incandescent_fixed_lighting_bulbs_count": { + "name": "incandescent_fixed_lighting_bulbs_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "blocked_chimneys_count": { + "name": "blocked_chimneys_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "draughtproofed_door_count": { + "name": "draughtproofed_door_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "energy_rating_average": { + "name": "energy_rating_average", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "low_energy_fixed_lighting_bulbs_count": { + "name": "low_energy_fixed_lighting_bulbs_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "fixed_lighting_outlets_count": { + "name": "fixed_lighting_outlets_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "low_energy_fixed_lighting_outlets_count": { + "name": "low_energy_fixed_lighting_outlets_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "number_of_storeys": { + "name": "number_of_storeys", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "any_unheated_rooms": { + "name": "any_unheated_rooms", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "hydro": { + "name": "hydro", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "photovoltaic_array": { + "name": "photovoltaic_array", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "waste_water_heat_recovery": { + "name": "waste_water_heat_recovery", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pressure_test": { + "name": "pressure_test", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "pressure_test_certificate_number": { + "name": "pressure_test_certificate_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "percent_draughtproofed": { + "name": "percent_draughtproofed", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "insulated_door_u_value": { + "name": "insulated_door_u_value", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "multiple_glazed_proportion": { + "name": "multiple_glazed_proportion", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "windows_transmission_u_value": { + "name": "windows_transmission_u_value", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "windows_transmission_data_source": { + "name": "windows_transmission_data_source", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "windows_transmission_solar_transmittance": { + "name": "windows_transmission_solar_transmittance", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_gas_connection_available": { + "name": "energy_gas_connection_available", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "energy_meter_type": { + "name": "energy_meter_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "energy_pv_battery_count": { + "name": "energy_pv_battery_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "energy_wind_turbines_count": { + "name": "energy_wind_turbines_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "energy_gas_smart_meter_present": { + "name": "energy_gas_smart_meter_present", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "energy_is_dwelling_export_capable": { + "name": "energy_is_dwelling_export_capable", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "energy_wind_turbines_terrain_type": { + "name": "energy_wind_turbines_terrain_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "energy_electricity_smart_meter_present": { + "name": "energy_electricity_smart_meter_present", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "energy_pv_connection": { + "name": "energy_pv_connection", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "energy_pv_percent_roof_area": { + "name": "energy_pv_percent_roof_area", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "energy_pv_battery_capacity": { + "name": "energy_pv_battery_capacity", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_wind_turbine_hub_height": { + "name": "energy_wind_turbine_hub_height", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_wind_turbine_rotor_diameter": { + "name": "energy_wind_turbine_rotor_diameter", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_pv_diverter_present": { + "name": "energy_pv_diverter_present", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "heating_cylinder_size": { + "name": "heating_cylinder_size", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_water_heating_code": { + "name": "heating_water_heating_code", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_water_heating_fuel": { + "name": "heating_water_heating_fuel", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_immersion_heating_type": { + "name": "heating_immersion_heating_type", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_insulation_type": { + "name": "heating_cylinder_insulation_type", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_thermostat": { + "name": "heating_cylinder_thermostat", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "heating_secondary_fuel_type": { + "name": "heating_secondary_fuel_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_secondary_heating_type": { + "name": "heating_secondary_heating_type", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_insulation_thickness_mm": { + "name": "heating_cylinder_insulation_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_volume_measured_l": { + "name": "heating_cylinder_volume_measured_l", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_heat_loss": { + "name": "heating_cylinder_heat_loss", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "heating_wwhrs_index_number_1": { + "name": "heating_wwhrs_index_number_1", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_wwhrs_index_number_2": { + "name": "heating_wwhrs_index_number_2", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_shower_outlet_type": { + "name": "heating_shower_outlet_type", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_shower_wwhrs": { + "name": "heating_shower_wwhrs", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_type": { + "name": "ventilation_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ventilation_draught_lobby": { + "name": "ventilation_draught_lobby", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "ventilation_pressure_test": { + "name": "ventilation_pressure_test", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ventilation_open_flues_count": { + "name": "ventilation_open_flues_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_closed_flues_count": { + "name": "ventilation_closed_flues_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_boiler_flues_count": { + "name": "ventilation_boiler_flues_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_other_flues_count": { + "name": "ventilation_other_flues_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_extract_fans_count": { + "name": "ventilation_extract_fans_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_passive_vents_count": { + "name": "ventilation_passive_vents_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_flueless_gas_fires_count": { + "name": "ventilation_flueless_gas_fires_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_in_pcdf_database": { + "name": "ventilation_in_pcdf_database", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "mechanical_ventilation": { + "name": "mechanical_ventilation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_duct_type": { + "name": "mechanical_vent_duct_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_duct_placement": { + "name": "mechanical_vent_duct_placement", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_duct_insulation": { + "name": "mechanical_vent_duct_insulation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_ventilation_index_number": { + "name": "mechanical_ventilation_index_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_measured_installation": { + "name": "mechanical_vent_measured_installation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_duct_insulation_level": { + "name": "mechanical_vent_duct_insulation_level", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "addendum_stone_walls": { + "name": "addendum_stone_walls", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "addendum_system_build": { + "name": "addendum_system_build", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "addendum_numbers": { + "name": "addendum_numbers", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_number_baths": { + "name": "heating_number_baths", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_number_baths_wwhrs": { + "name": "heating_number_baths_wwhrs", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_electric_shower_count": { + "name": "heating_electric_shower_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_mixer_shower_count": { + "name": "heating_mixer_shower_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_present": { + "name": "ventilation_present", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "ventilation_sheltered_sides": { + "name": "ventilation_sheltered_sides", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_has_suspended_timber_floor": { + "name": "ventilation_has_suspended_timber_floor", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "ventilation_suspended_timber_floor_sealed": { + "name": "ventilation_suspended_timber_floor_sealed", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "ventilation_has_draught_lobby": { + "name": "ventilation_has_draught_lobby", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "ventilation_air_permeability_ap4_m3_h_m2": { + "name": "ventilation_air_permeability_ap4_m3_h_m2", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "ventilation_air_permeability_ap50_m3_h_m2": { + "name": "ventilation_air_permeability_ap50_m3_h_m2", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "ventilation_mechanical_ventilation_kind": { + "name": "ventilation_mechanical_ventilation_kind", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "uq_epc_property_property_portfolio": { + "name": "uq_epc_property_property_portfolio", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "ix_epc_property_property_source": { + "name": "ix_epc_property_property_source", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_property_property_id_property_id_fk": { + "name": "epc_property_property_id_property_id_fk", + "tableFrom": "epc_property", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "epc_property_portfolio_id_portfolio_id_fk": { + "name": "epc_property_portfolio_id_portfolio_id_fk", + "tableFrom": "epc_property", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "epc_property_uploaded_file_id_uploaded_files_id_fk": { + "name": "epc_property_uploaded_file_id_uploaded_files_id_fk", + "tableFrom": "epc_property", + "tableTo": "uploaded_files", + "columnsFrom": [ + "uploaded_file_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_property_uploaded_file_id_unique": { + "name": "epc_property_uploaded_file_id_unique", + "nullsNotDistinct": false, + "columns": [ + "uploaded_file_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_property_energy_performance": { + "name": "epc_property_energy_performance", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "energy_rating_current": { + "name": "energy_rating_current", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "energy_consumption_current": { + "name": "energy_consumption_current", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "environmental_impact_current": { + "name": "environmental_impact_current", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_cost_current": { + "name": "heating_cost_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lighting_cost_current": { + "name": "lighting_cost_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "hot_water_cost_current": { + "name": "hot_water_cost_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_emissions_current": { + "name": "co2_emissions_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_emissions_current_per_floor_area": { + "name": "co2_emissions_current_per_floor_area", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "current_energy_efficiency_band": { + "name": "current_energy_efficiency_band", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "energy_rating_potential": { + "name": "energy_rating_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_consumption_potential": { + "name": "energy_consumption_potential", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "environmental_impact_potential": { + "name": "environmental_impact_potential", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_cost_potential": { + "name": "heating_cost_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lighting_cost_potential": { + "name": "lighting_cost_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "hot_water_cost_potential": { + "name": "hot_water_cost_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_emissions_potential": { + "name": "co2_emissions_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "potential_energy_efficiency_band": { + "name": "potential_energy_efficiency_band", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_property_energy_performance_epc_property_id_epc_property_id_fk": { + "name": "epc_property_energy_performance_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_property_energy_performance", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_property_energy_performance_epc_property_id_unique": { + "name": "epc_property_energy_performance_epc_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "epc_property_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_renewable_heat_incentive": { + "name": "epc_renewable_heat_incentive", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "space_heating_kwh": { + "name": "space_heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "water_heating_kwh": { + "name": "water_heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "impact_of_loft_insulation_kwh": { + "name": "impact_of_loft_insulation_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "impact_of_cavity_insulation_kwh": { + "name": "impact_of_cavity_insulation_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "impact_of_solid_wall_insulation_kwh": { + "name": "impact_of_solid_wall_insulation_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_renewable_heat_incentive_epc_property_id_epc_property_id_fk": { + "name": "epc_renewable_heat_incentive_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_renewable_heat_incentive", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_renewable_heat_incentive_epc_property_id_unique": { + "name": "epc_renewable_heat_incentive_epc_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "epc_property_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_roof_window": { + "name": "epc_roof_window", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "roof_window_index": { + "name": "roof_window_index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "area_m2": { + "name": "area_m2", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "u_value_raw": { + "name": "u_value_raw", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "orientation": { + "name": "orientation", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "pitch_deg": { + "name": "pitch_deg", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "g_perpendicular": { + "name": "g_perpendicular", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "frame_factor": { + "name": "frame_factor", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "glazing_type": { + "name": "glazing_type", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "window_location": { + "name": "window_location", + "type": "jsonb", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "uq_epc_roof_window_property_index": { + "name": "uq_epc_roof_window_property_index", + "columns": [ + { + "expression": "epc_property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "roof_window_index", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_roof_window_epc_property_id_epc_property_id_fk": { + "name": "epc_roof_window_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_roof_window", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_room_in_roof": { + "name": "epc_room_in_roof", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_building_part_id": { + "name": "epc_building_part_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "floor_area": { + "name": "floor_area", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "construction_age_band": { + "name": "construction_age_band", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "common_wall_length_m": { + "name": "common_wall_length_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "common_wall_height_m": { + "name": "common_wall_height_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "gable_1_length_m": { + "name": "gable_1_length_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "gable_1_height_m": { + "name": "gable_1_height_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "gable_2_length_m": { + "name": "gable_2_length_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "gable_2_height_m": { + "name": "gable_2_height_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_room_in_roof_epc_building_part_id_epc_building_part_id_fk": { + "name": "epc_room_in_roof_epc_building_part_id_epc_building_part_id_fk", + "tableFrom": "epc_room_in_roof", + "tableTo": "epc_building_part", + "columnsFrom": [ + "epc_building_part_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_room_in_roof_epc_building_part_id_unique": { + "name": "epc_room_in_roof_epc_building_part_id_unique", + "nullsNotDistinct": false, + "columns": [ + "epc_building_part_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_room_in_roof_surface": { + "name": "epc_room_in_roof_surface", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_room_in_roof_id": { + "name": "epc_room_in_roof_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "surface_index": { + "name": "surface_index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "area_m2": { + "name": "area_m2", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "insulation_thickness_mm": { + "name": "insulation_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "insulation_type": { + "name": "insulation_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "u_value": { + "name": "u_value", + "type": "double precision", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "uq_epc_room_in_roof_surface_index": { + "name": "uq_epc_room_in_roof_surface_index", + "columns": [ + { + "expression": "epc_room_in_roof_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "surface_index", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_room_in_roof_surface_epc_room_in_roof_id_epc_room_in_roof_id_fk": { + "name": "epc_room_in_roof_surface_epc_room_in_roof_id_epc_room_in_roof_id_fk", + "tableFrom": "epc_room_in_roof_surface", + "tableTo": "epc_room_in_roof", + "columnsFrom": [ + "epc_room_in_roof_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_window": { + "name": "epc_window", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "glazing_gap": { + "name": "glazing_gap", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "orientation": { + "name": "orientation", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "window_type": { + "name": "window_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "glazing_type": { + "name": "glazing_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "window_width": { + "name": "window_width", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "window_height": { + "name": "window_height", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "draught_proofed": { + "name": "draught_proofed", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "window_location": { + "name": "window_location", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "window_wall_type": { + "name": "window_wall_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "permanent_shutters_present": { + "name": "permanent_shutters_present", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "frame_material": { + "name": "frame_material", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "frame_factor": { + "name": "frame_factor", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "permanent_shutters_insulated": { + "name": "permanent_shutters_insulated", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "transmission_u_value": { + "name": "transmission_u_value", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "transmission_data_source": { + "name": "transmission_data_source", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "transmission_solar_transmittance": { + "name": "transmission_solar_transmittance", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_window_epc_property_id_epc_property_id_fk": { + "name": "epc_window_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_window", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_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 + }, + "certificate_number": { + "name": "certificate_number", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "landlord_property_id": { + "name": "landlord_property_id", + "type": "text", + "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 + }, + "user_inputted_address": { + "name": "user_inputted_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_inputted_postcode": { + "name": "user_inputted_postcode", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lexiscore": { + "name": "lexiscore", + "type": "real", + "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 + }, + "installed_measures_sap_point_adjustment": { + "name": "installed_measures_sap_point_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "is_sap_points_adjusted_for_installed_measures": { + "name": "is_sap_points_adjusted_for_installed_measures", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "original_sap_points": { + "name": "original_sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lodged_sap_points": { + "name": "lodged_sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lodged_epc_rating": { + "name": "lodged_epc_rating", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "marked_for_deletion": { + "name": "marked_for_deletion", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "uq_property_portfolio_uprn": { + "name": "uq_property_portfolio_uprn", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"property\".\"uprn\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "ix_property_portfolio": { + "name": "ix_property_portfolio", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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_baseline_performance": { + "name": "property_baseline_performance", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "lodged_sap_score": { + "name": "lodged_sap_score", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "lodged_epc_band": { + "name": "lodged_epc_band", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "lodged_co2_emissions_t_per_yr": { + "name": "lodged_co2_emissions_t_per_yr", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lodged_primary_energy_intensity_kwh_per_m2_yr": { + "name": "lodged_primary_energy_intensity_kwh_per_m2_yr", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "effective_sap_score": { + "name": "effective_sap_score", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "effective_epc_band": { + "name": "effective_epc_band", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "effective_co2_emissions_t_per_yr": { + "name": "effective_co2_emissions_t_per_yr", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "effective_primary_energy_intensity_kwh_per_m2_yr": { + "name": "effective_primary_energy_intensity_kwh_per_m2_yr", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "rebaseline_reason": { + "name": "rebaseline_reason", + "type": "rebaseline_reason", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "space_heating_kwh": { + "name": "space_heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "water_heating_kwh": { + "name": "water_heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "fuel_rates_period": { + "name": "fuel_rates_period", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "heating_kwh": { + "name": "heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "heating_cost_gbp": { + "name": "heating_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "hot_water_kwh": { + "name": "hot_water_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "hot_water_cost_gbp": { + "name": "hot_water_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lighting_kwh": { + "name": "lighting_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lighting_cost_gbp": { + "name": "lighting_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "appliances_kwh": { + "name": "appliances_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "appliances_cost_gbp": { + "name": "appliances_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cooking_kwh": { + "name": "cooking_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cooking_cost_gbp": { + "name": "cooking_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "pumps_fans_kwh": { + "name": "pumps_fans_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "pumps_fans_cost_gbp": { + "name": "pumps_fans_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cooling_kwh": { + "name": "cooling_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cooling_cost_gbp": { + "name": "cooling_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "standing_charges_gbp": { + "name": "standing_charges_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "seg_credit_gbp": { + "name": "seg_credit_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "total_annual_bill_gbp": { + "name": "total_annual_bill_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "property_baseline_performance_property_id_property_id_fk": { + "name": "property_baseline_performance_property_id_property_id_fk", + "tableFrom": "property_baseline_performance", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "property_baseline_performance_property_id_unique": { + "name": "property_baseline_performance_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "property_id" + ] + } + }, + "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 + }, + "lodgement_date": { + "name": "lodgement_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "is_expired": { + "name": "is_expired", + "type": "boolean", + "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 + }, + "sap_05_overwritten": { + "name": "sap_05_overwritten", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "sap_05_score": { + "name": "sap_05_score", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "sap_05_epc_rating": { + "name": "sap_05_epc_rating", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": 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 + }, + "original_co2_emissions": { + "name": "original_co2_emissions", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "original_primary_energy_consumption": { + "name": "original_primary_energy_consumption", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "original_current_energy_demand": { + "name": "original_current_energy_demand", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "original_current_energy_demand_heating_hotwater": { + "name": "original_current_energy_demand_heating_hotwater", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "installed_measures_co2_adjustment": { + "name": "installed_measures_co2_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "installed_measures_energy_demand_adjustment": { + "name": "installed_measures_energy_demand_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "installed_measures_total_energy_bill_adjustment": { + "name": "installed_measures_total_energy_bill_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "installed_measures_heat_demand_adjustment": { + "name": "installed_measures_heat_demand_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "is_epc_adjusted_for_installed_measures": { + "name": "is_epc_adjusted_for_installed_measures", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "lodged_co2_emissions": { + "name": "lodged_co2_emissions", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lodged_heat_demand": { + "name": "lodged_heat_demand", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "has_been_remodelled": { + "name": "has_been_remodelled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "environment_impact_current": { + "name": "environment_impact_current", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "uq_property_details_epc_property_portfolio": { + "name": "uq_property_details_epc_property_portfolio", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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": { + "uq_property_details_spatial_uprn": { + "name": "uq_property_details_spatial_uprn", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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.installed_measure": { + "name": "installed_measure", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "measure_type": { + "name": "measure_type", + "type": "measure_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "installed_at": { + "name": "installed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "sap_points": { + "name": "sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "carbon_savings": { + "name": "carbon_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "kwh_savings": { + "name": "kwh_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "bill_savings": { + "name": "bill_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "heat_demand_savings": { + "name": "heat_demand_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + } + }, + "indexes": { + "idx_installed_measure_uprn": { + "name": "idx_installed_measure_uprn", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_installed_measure_uprn_active": { + "name": "idx_installed_measure_uprn_active", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"installed_measure\".\"is_active\" = true", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_installed_measure_measure_type": { + "name": "idx_installed_measure_measure_type", + "columns": [ + { + "expression": "measure_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_installed_measure_uprn_measure": { + "name": "idx_installed_measure_uprn_measure", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "measure_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"installed_measure\".\"is_active\" = true", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "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 + }, + "post_sap_points": { + "name": "post_sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "post_epc_rating": { + "name": "post_epc_rating", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "post_co2_emissions": { + "name": "post_co2_emissions", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_savings": { + "name": "co2_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "post_energy_bill": { + "name": "post_energy_bill", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_bill_savings": { + "name": "energy_bill_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "post_energy_consumption": { + "name": "post_energy_consumption", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_consumption_savings": { + "name": "energy_consumption_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "valuation_post_retrofit": { + "name": "valuation_post_retrofit", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "valuation_increase": { + "name": "valuation_increase", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cost_of_works": { + "name": "cost_of_works", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "contingency_cost": { + "name": "contingency_cost", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "plan_type": { + "name": "plan_type", + "type": "plan_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_plan_portfolio_scenario": { + "name": "idx_plan_portfolio_scenario", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scenario_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_plan_latest_per_property": { + "name": "idx_plan_latest_per_property", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scenario_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_plan_property_default_latest": { + "name": "idx_plan_property_default_latest", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "where": "is_default = true", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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": { + "idx_plan_recommendations_plan_id": { + "name": "idx_plan_recommendations_plan_id", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_plan_recommendations_plan_rec": { + "name": "idx_plan_recommendations_plan_rec", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "recommendation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_plan_recommendations_recommendation_id": { + "name": "idx_plan_recommendations_recommendation_id", + "columns": [ + { + "expression": "recommendation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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 + }, + "plan_id": { + "name": "plan_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "material_id": { + "name": "material_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "material_quantity": { + "name": "material_quantity", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "material_quantity_unit": { + "name": "material_quantity_unit", + "type": "unit_quantity", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "material_depth": { + "name": "material_depth", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "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": { + "recommendation_property_id_idx": { + "name": "recommendation_property_id_idx", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_plan_id": { + "name": "idx_recommendation_plan_id", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_active_defaults": { + "name": "idx_recommendation_active_defaults", + "columns": [ + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"recommendation\".\"default\" = true AND \"recommendation\".\"already_installed\" = false", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_active_id_property": { + "name": "idx_recommendation_active_id_property", + "columns": [ + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"recommendation\".\"default\" = true AND \"recommendation\".\"already_installed\" = false", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_plan_default": { + "name": "idx_recommendation_plan_default", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "measure_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "estimated_cost", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"recommendation\".\"default\" = true AND \"recommendation\".\"already_installed\" = false", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_material_id": { + "name": "idx_recommendation_material_id", + "columns": [ + { + "expression": "material_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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" + }, + "recommendation_plan_id_plan_id_fk": { + "name": "recommendation_plan_id_plan_id_fk", + "tableFrom": "recommendation", + "tableTo": "plan", + "columnsFrom": [ + "plan_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "recommendation_material_id_material_id_fk": { + "name": "recommendation_material_id_material_id_fk", + "tableFrom": "recommendation", + "tableTo": "material", + "columnsFrom": [ + "material_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "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": { + "recommendation_materials_recommendation_id_idx": { + "name": "recommendation_materials_recommendation_id_idx", + "columns": [ + { + "expression": "recommendation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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": "cascade", + "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 + }, + "fabric_first": { + "name": "fabric_first", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "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.property_removal_requests": { + "name": "property_removal_requests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'removal'" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "requested_by": { + "name": "requested_by", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "requested_at": { + "name": "requested_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "reviewed_by": { + "name": "reviewed_by", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "reviewed_at": { + "name": "reviewed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "original_batch": { + "name": "original_batch", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_removal_requests_deal_id": { + "name": "idx_removal_requests_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_removal_requests_portfolio_id": { + "name": "idx_removal_requests_portfolio_id", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "property_removal_requests_portfolio_id_portfolio_id_fk": { + "name": "property_removal_requests_portfolio_id_portfolio_id_fk", + "tableFrom": "property_removal_requests", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "property_removal_requests_requested_by_user_id_fk": { + "name": "property_removal_requests_requested_by_user_id_fk", + "tableFrom": "property_removal_requests", + "tableTo": "user", + "columnsFrom": [ + "requested_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "property_removal_requests_reviewed_by_user_id_fk": { + "name": "property_removal_requests_reviewed_by_user_id_fk", + "tableFrom": "property_removal_requests", + "tableTo": "user", + "columnsFrom": [ + "reviewed_by" + ], + "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.survey_requests": { + "name": "survey_requests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "survey_type": { + "name": "survey_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "requested_by": { + "name": "requested_by", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "requested_at": { + "name": "requested_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "fulfilled_at": { + "name": "fulfilled_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_survey_requests_deal_id": { + "name": "idx_survey_requests_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_survey_requests_portfolio_id": { + "name": "idx_survey_requests_portfolio_id", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "survey_requests_portfolio_id_portfolio_id_fk": { + "name": "survey_requests_portfolio_id_portfolio_id_fk", + "tableFrom": "survey_requests", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "survey_requests_requested_by_user_id_fk": { + "name": "survey_requests_requested_by_user_id_fk", + "tableFrom": "survey_requests", + "tableTo": "user", + "columnsFrom": [ + "requested_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.portfolio_tag": { + "name": "portfolio_tag", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "colour": { + "name": "colour", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "uq_portfolio_tag_portfolio_lower_name": { + "name": "uq_portfolio_tag_portfolio_lower_name", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"name\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "portfolio_tag_portfolio_id_portfolio_id_fk": { + "name": "portfolio_tag_portfolio_id_portfolio_id_fk", + "tableFrom": "portfolio_tag", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_tag": { + "name": "property_tag", + "schema": "", + "columns": { + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "tag_id": { + "name": "tag_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "ix_property_tag_tag": { + "name": "ix_property_tag_tag", + "columns": [ + { + "expression": "tag_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "property_tag_property_id_property_id_fk": { + "name": "property_tag_property_id_property_id_fk", + "tableFrom": "property_tag", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "property_tag_tag_id_portfolio_tag_id_fk": { + "name": "property_tag_tag_id_portfolio_tag_id_fk", + "tableFrom": "property_tag", + "tableTo": "portfolio_tag", + "columnsFrom": [ + "tag_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "property_tag_property_id_tag_id_pk": { + "name": "property_tag_property_id_tag_id_pk", + "columns": [ + "property_id", + "tag_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sub_task": { + "name": "sub_task", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "task_id": { + "name": "task_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "job_started": { + "name": "job_started", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "job_completed": { + "name": "job_completed", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'In Progress'" + }, + "service": { + "name": "service", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "inputs": { + "name": "inputs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "outputs": { + "name": "outputs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cloud_logs_url": { + "name": "cloud_logs_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "sub_task_task_id_tasks_id_fk": { + "name": "sub_task_task_id_tasks_id_fk", + "tableFrom": "sub_task", + "tableTo": "tasks", + "columnsFrom": [ + "task_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tasks": { + "name": "tasks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "task_source": { + "name": "task_source", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "job_started": { + "name": "job_started", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "job_completed": { + "name": "job_completed", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'In Progress'" + }, + "service": { + "name": "service", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "source", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "source_id": { + "name": "source_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "inputs": { + "name": "inputs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team": { + "name": "team", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "uuid", + "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": { + "team_org_id_organisation_id_fk": { + "name": "team_org_id_organisation_id_fk", + "tableFrom": "team", + "tableTo": "organisation", + "columnsFrom": [ + "org_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_members": { + "name": "team_members", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "team_id": { + "name": "team_id", + "type": "uuid", + "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": { + "team_members_user_id_user_id_fk": { + "name": "team_members_user_id_user_id_fk", + "tableFrom": "team_members", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "team_members_team_id_team_id_fk": { + "name": "team_members_team_id_team_id_fk", + "tableFrom": "team_members", + "tableTo": "team", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_portfolio_permissions": { + "name": "team_portfolio_permissions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "team_id": { + "name": "team_id", + "type": "uuid", + "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": { + "team_portfolio_permissions_team_id_team_id_fk": { + "name": "team_portfolio_permissions_team_id_team_id_fk", + "tableFrom": "team_portfolio_permissions", + "tableTo": "team", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "team_portfolio_permissions_portfolio_id_portfolio_id_fk": { + "name": "team_portfolio_permissions_portfolio_id_portfolio_id_fk", + "tableFrom": "team_portfolio_permissions", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.uploaded_files": { + "name": "uploaded_files", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "s3_file_bucket": { + "name": "s3_file_bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "s3_file_key": { + "name": "s3_file_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "s3_upload_timestamp": { + "name": "s3_upload_timestamp", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "landlord_property_id": { + "name": "landlord_property_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "hubspot_listing_id": { + "name": "hubspot_listing_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "file_type": { + "name": "file_type", + "type": "file_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "file_source": { + "name": "file_source", + "type": "file_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uploaded_by": { + "name": "uploaded_by", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "work_order_id": { + "name": "work_order_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "project_workstream_evidence_requirement_id": { + "name": "project_workstream_evidence_requirement_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "uploaded_files_uploaded_by_user_id_fk": { + "name": "uploaded_files_uploaded_by_user_id_fk", + "tableFrom": "uploaded_files", + "tableTo": "user", + "columnsFrom": [ + "uploaded_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "uploaded_files_work_order_id_work_order_id_fk": { + "name": "uploaded_files_work_order_id_work_order_id_fk", + "tableFrom": "uploaded_files", + "tableTo": "work_order", + "columnsFrom": [ + "work_order_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "uploaded_files_project_workstream_evidence_requirement_id_project_workstream_evidence_requirement_id_fk": { + "name": "uploaded_files_project_workstream_evidence_requirement_id_project_workstream_evidence_requirement_id_fk", + "tableFrom": "uploaded_files", + "tableTo": "project_workstream_evidence_requirement", + "columnsFrom": [ + "project_workstream_evidence_requirement_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_defined_deal_measures": { + "name": "user_defined_deal_measures", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "user_defined_deal_measure_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "pushed_at": { + "name": "pushed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "confirmed_in_hubspot_at": { + "name": "confirmed_in_hubspot_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_user_defined_deal_measures_deal_id": { + "name": "idx_user_defined_deal_measures_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_user_defined_deal_measures_source": { + "name": "idx_user_defined_deal_measures_source", + "columns": [ + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_defined_deal_measures_created_by_user_id_user_id_fk": { + "name": "user_defined_deal_measures_created_by_user_id_user_id_fk", + "tableFrom": "user_defined_deal_measures", + "tableTo": "user", + "columnsFrom": [ + "created_by_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_portfolio_config": { + "name": "user_portfolio_config", + "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 + }, + "starred_at": { + "name": "starred_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "folder_id": { + "name": "folder_id", + "type": "bigint", + "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": { + "idx_user_portfolio_config_folder": { + "name": "idx_user_portfolio_config_folder", + "columns": [ + { + "expression": "folder_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_portfolio_config_user_id_user_id_fk": { + "name": "user_portfolio_config_user_id_user_id_fk", + "tableFrom": "user_portfolio_config", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_portfolio_config_portfolio_id_portfolio_id_fk": { + "name": "user_portfolio_config_portfolio_id_portfolio_id_fk", + "tableFrom": "user_portfolio_config", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_portfolio_config_folder_owner_fk": { + "name": "user_portfolio_config_folder_owner_fk", + "tableFrom": "user_portfolio_config", + "tableTo": "user_portfolio_folders", + "columnsFrom": [ + "folder_id", + "user_id" + ], + "columnsTo": [ + "id", + "user_id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_portfolio_config_user_portfolio_unique": { + "name": "user_portfolio_config_user_portfolio_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "portfolio_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_portfolio_folders": { + "name": "user_portfolio_folders", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "position": { + "name": "position", + "type": "integer", + "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": { + "idx_user_portfolio_folders_user_position": { + "name": "idx_user_portfolio_folders_user_position", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "position", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_portfolio_folders_user_id_user_id_fk": { + "name": "user_portfolio_folders_user_id_user_id_fk", + "tableFrom": "user_portfolio_folders", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_portfolio_folders_id_user_unique": { + "name": "user_portfolio_folders_id_user_unique", + "nullsNotDistinct": false, + "columns": [ + "id", + "user_id" + ] + } + }, + "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.authRateLimits": { + "name": "authRateLimits", + "schema": "", + "columns": { + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "count": { + "name": "count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "window_start": { + "name": "window_start", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "authRateLimits_scope_key_pk": { + "name": "authRateLimits_scope_key_pk", + "columns": [ + "scope", + "key" + ] + } + }, + "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 + }, + "code_hash": { + "name": "code_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.whlg": { + "name": "whlg", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.aspect_type": { + "name": "aspect_type", + "schema": "public", + "values": [ + "material", + "condition", + "type", + "area", + "configuration", + "presence", + "risk", + "severity", + "location", + "finish", + "insulation", + "pointing", + "spalling", + "lintels", + "cladding", + "category", + "quantity", + "adequacy", + "rating", + "strategy", + "extent", + "distribution", + "structure", + "covering", + "fire_rating", + "external_decoration", + "work_required", + "age_band", + "construction_type", + "classification", + "system" + ] + }, + "public.element_type": { + "name": "element_type", + "schema": "public", + "values": [ + "property", + "property_construction_type", + "property_classification", + "property_age_band", + "storey_count", + "floor_level", + "floor_level_front_door", + "accessible_housing_register", + "asbestos", + "quality_standard", + "ccu", + "passenger_lift", + "stairlift", + "disabled_hoist_tracking", + "disabled_facilities", + "steps_to_front_door", + "roof", + "pitched_roof_covering", + "flat_roof_covering", + "rainwater_goods", + "loft_insulation", + "porch_canopy", + "chimney", + "fascia", + "soffit", + "fascia_soffit_bargeboards", + "gutters", + "store_roof", + "garage_roof", + "garage_and_store_roof", + "external_wall", + "external_noise_insulation", + "primary_wall", + "secondary_wall", + "downpipes", + "external_decoration", + "cladding", + "spandrel_panels", + "garage_walls", + "party_wall_fire_break", + "external_brickwork_pointing", + "internal_downpipes_external_area", + "external_windows", + "communal_windows", + "secondary_glazing", + "store_windows", + "garage_windows", + "garage_and_store_windows", + "external_door", + "front_door", + "rear_door", + "store_door", + "garage_door", + "garage_and_store_door", + "communal_entrance_door", + "main_door", + "block_entrance_door", + "lintel", + "patio_french_door", + "door_entry_handset", + "paths_and_hardstandings", + "parking_areas", + "boundary_walls", + "front_fencing", + "rear_fencing", + "side_fencing", + "rear_gate", + "front_gate", + "gates", + "retaining_walls", + "private_balcony", + "balcony_balustrade", + "outbuildings", + "garage_structure", + "paving", + "roads", + "soil_and_vent", + "solar_thermals", + "drop_kerb", + "outbuilding_overhaul", + "external_structural_defects", + "access_ramp", + "kitchen", + "kitchen_space_layout", + "tenant_installed_kitchen", + "kitchen_extractor_fan", + "bathroom", + "secondary_bathroom", + "secondary_toilet", + "bathroom_extractor_fan", + "additional_wc_or_whb", + "bathroom_remaining_life_source", + "kitchen_remaining_life_source", + "central_heating", + "heating_boiler", + "heating_distribution", + "secondary_heating", + "hot_water_system", + "cold_water_storage", + "heating_system", + "boiler_fuel", + "water_heating", + "programmable_heating", + "community_heating", + "gas_available", + "heat_recovery_units", + "heating_improvements", + "electrical_wiring", + "consumer_unit", + "smoke_detection", + "heat_detection", + "carbon_monoxide_detection", + "fire_door_rating", + "fire_risk_assessment", + "internal_wiring", + "electrics", + "communal_heating", + "communal_boiler", + "communal_electrics", + "communal_fire_alarm", + "communal_emergency_lighting", + "communal_door_entry", + "communal_cctv", + "communal_bin_store", + "communal_bin_store_doors", + "communal_bin_store_walls", + "communal_bin_store_roof", + "communal_refuse_chute", + "communal_floor_covering", + "communal_kitchen", + "communal_bathroom", + "communal_toilets", + "communal_gates", + "communal_lift", + "communal_passenger_lift", + "communal_balcony_walkway", + "communal_entrance", + "communal_internal_decorations", + "communal_internal_floor", + "communal_walkways", + "communal_external_doors", + "communal_stairs", + "communal_aerial", + "communal_aov", + "communal_internal_doors", + "communal_lateral_mains", + "communal_lighting", + "communal_lighting_conductor", + "communal_store_roof", + "communal_store_walls", + "communal_store_doors", + "communal_warden_call_system", + "communal_bms", + "communal_booster_pump", + "communal_dry_riser", + "communal_wet_riser", + "communal_cold_water_storage", + "communal_sprinkler", + "communal_plug_sockets", + "communal_circulation_space", + "ffhh_damp", + "ffhh_hold_and_cold_water", + "ffhh_drainage_lavatories", + "ffhh_neglected", + "ffhh_natural_light", + "ffhh_ventilation", + "ffhh_food_prep_and_washup", + "ffhh_unsafe_layout", + "ffhh_unstable_building", + "hhsrs_damp_and_mould", + "hhsrs_excess_cold", + "hhsrs_excess_heat", + "hhsrs_asbestos_and_mmf", + "hhsrs_biocides", + "hhsrs_carbon_monoxide", + "hhsrs_lead", + "hhsrs_radiation", + "hhsrs_uncombusted_fuel_gas", + "hhsrs_volatile_organic_compounds", + "hhsrs_crowding_and_space", + "hhsrs_entry_by_intruders", + "hhsrs_lighting", + "hhsrs_noise", + "hhsrs_domestic_hygiene_pests_refuse", + "hhsrs_food_safety", + "hhsrs_personal_hygiene_sanitation", + "hhsrs_water_supply", + "hhsrs_falls_associated_with_baths", + "hhsrs_falls_on_level_surfaces", + "hhsrs_falls_on_stairs", + "hhsrs_falls_between_levels", + "hhsrs_electrical_hazards", + "hhsrs_fire", + "hhsrs_flames_hot_surfaces", + "hhsrs_collision_and_entrapment", + "hhsrs_collision_hazards_low_headroom", + "hhsrs_explosions", + "hhsrs_ergonomics", + "hhsrs_structural_collapse", + "hhsrs_amenities" + ] + }, + "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.inspection_archetype_2": { + "name": "inspection_archetype_2", + "schema": "public", + "values": [ + "detached", + "mid-terrace", + "enclosed mid-terrace", + "end-terrace", + "enclosed end-terrace", + "semi-detached" + ] + }, + "public.inspection_archetype": { + "name": "inspection_archetype", + "schema": "public", + "values": [ + "Bungalow", + "Flat", + "Maisonette", + "House", + "non-domestic" + ] + }, + "public.inspection_borescoped": { + "name": "inspection_borescoped", + "schema": "public", + "values": [ + "yes", + "no", + "refused" + ] + }, + "public.inspections_access_issues": { + "name": "inspections_access_issues", + "schema": "public", + "values": [ + "see notes", + "damp issues", + "foliage on walls", + "bushes against wall", + "trees around/anove property", + "high rise block flats/maisonettes", + "conservatory", + "lean-to", + "garage", + "extension", + "decking", + "shed against wall" + ] + }, + "public.inspections_cladding": { + "name": "inspections_cladding", + "schema": "public", + "values": [ + "none", + "cladded with “sufficient space to fill the wall”", + "cladded with “insufficient space to fill the wall”" + ] + }, + "public.inspections_insulation_material": { + "name": "inspections_insulation_material", + "schema": "public", + "values": [ + "empty 50-90", + "empty 100+", + "empty 30-40", + "empty less than 30", + "loose fibre/wool", + "eps/celo/king", + "fibre batts - with cavity", + "fibre batts - no cavity", + "loose bead", + "glued bead", + "formaldehyde", + "bubble wrap", + "poly chunks" + ] + }, + "public.inspections_rendered": { + "name": "inspections_rendered", + "schema": "public", + "values": [ + "no render", + "rendered with “insufficient” space between dpc and render", + "rendered with “sufficient” space between dpc and render" + ] + }, + "public.inspections_roof_orientation": { + "name": "inspections_roof_orientation", + "schema": "public", + "values": [ + "north", + "east", + "south", + "west", + "north-east", + "north-west", + "south-east", + "south-west", + "n/s split", + "e/w split", + "ne/sw split", + "nw/se split", + "flat roof", + "no roof", + "roof too small", + "already has solar pv" + ] + }, + "public.inspections_tile_hung": { + "name": "inspections_tile_hung", + "schema": "public", + "values": [ + "yes", + "no", + "first floor flats are tile hung" + ] + }, + "public.inspections_wall_construction": { + "name": "inspections_wall_construction", + "schema": "public", + "values": [ + "cavity", + "solid", + "system built", + "timber framed", + "steel framed", + "re-walled cavity", + "mansard pre-fab", + "mansard ewi", + "mansard re-walled" + ] + }, + "public.inspections_wall_insulation": { + "name": "inspections_wall_insulation", + "schema": "public", + "values": [ + "empty cavity", + "filled at build", + "partial", + "retro drilled", + "ewi", + "iwi", + "solid non-cavity", + "system built", + "timber framed", + "steel framed" + ] + }, + "public.built_form_type": { + "name": "built_form_type", + "schema": "public", + "values": [ + "Detached", + "Semi-Detached", + "Mid-Terrace", + "End-Terrace", + "Enclosed Mid-Terrace", + "Enclosed End-Terrace", + "Not Recorded", + "Unknown" + ] + }, + "public.construction_age_band": { + "name": "construction_age_band", + "schema": "public", + "values": [ + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "Unknown" + ] + }, + "public.glazing": { + "name": "glazing", + "schema": "public", + "values": [ + "Single glazing", + "Double glazing, 2002 or later", + "Double glazing, pre-2002", + "Triple glazing, pre-2002", + "Triple glazing, 2002 or later", + "Mixed glazing", + "Secondary glazing", + "Unknown" + ] + }, + "public.main_fuel": { + "name": "main_fuel", + "schema": "public", + "values": [ + "mains gas", + "mains gas (community)", + "electricity", + "electricity (community)", + "LPG (bulk)", + "bottled LPG", + "LPG special condition", + "oil", + "house coal", + "smokeless coal", + "dual fuel (mineral and wood)", + "biomass (community)", + "wood logs", + "Unknown" + ] + }, + "public.main_heating_system": { + "name": "main_heating_system", + "schema": "public", + "values": [ + "Gas boiler, combi", + "Gas boiler, regular", + "Gas CPSU", + "Electric storage heaters, old", + "Electric storage heaters, slimline", + "Electric storage heaters, convector", + "Electric storage heaters, fan", + "Direct-acting electric", + "Electric room heaters", + "Solid fuel room heater, closed", + "Air source heat pump", + "Community heating, boilers", + "Community heating, CHP and boilers", + "Oil room heater, 2000 or later", + "Gas room heater, condensing fire", + "Gas room heater, decorative fuel-effect", + "Gas room heater, flush live-effect", + "Gas room heater, open flue 1980 or later", + "Gas room heater, open flue pre-1980", + "Electric storage heaters, high heat retention", + "Solid fuel room heater, open fire", + "Solid fuel room heater, open fire with back boiler", + "Solid fuel room heater, closed with boiler", + "Electric boiler", + "Electric CPSU", + "Electric underfloor, in concrete slab (off-peak)", + "Electric underfloor, integrated storage and direct-acting", + "Electric underfloor, in screed above insulation", + "Unknown" + ] + }, + "public.override_source": { + "name": "override_source", + "schema": "public", + "values": [ + "classifier", + "user", + "os_places" + ] + }, + "public.property_type": { + "name": "property_type", + "schema": "public", + "values": [ + "House", + "Bungalow", + "Flat", + "Maisonette", + "Park home", + "Unknown" + ] + }, + "public.roof_type": { + "name": "roof_type", + "schema": "public", + "values": [ + "Flat, insulated", + "Flat, insulated (assumed)", + "Flat, limited insulation", + "Flat, limited insulation (assumed)", + "Flat, no insulation", + "Flat, no insulation (assumed)", + "Flat, 12 mm insulation", + "Flat, 25 mm insulation", + "Flat, 50 mm insulation", + "Flat, 75 mm insulation", + "Flat, 100 mm insulation", + "Flat, 125 mm insulation", + "Flat, 150 mm insulation", + "Flat, 175 mm insulation", + "Flat, 200 mm insulation", + "Flat, 225 mm insulation", + "Flat, 250 mm insulation", + "Flat, 270 mm insulation", + "Flat, 300 mm insulation", + "Flat, 350 mm insulation", + "Flat, 400 mm insulation", + "Flat, 400+ mm insulation", + "Pitched, insulated", + "Pitched, insulated (assumed)", + "Pitched, insulated at rafters", + "Pitched, limited insulation", + "Pitched, limited insulation (assumed)", + "Pitched, no insulation", + "Pitched, no insulation (assumed)", + "Pitched, Unknown loft insulation", + "Pitched, 0 mm loft insulation", + "Pitched, 12 mm loft insulation", + "Pitched, 25 mm loft insulation", + "Pitched, 50 mm loft insulation", + "Pitched, 75 mm loft insulation", + "Pitched, 100 mm loft insulation", + "Pitched, 125 mm loft insulation", + "Pitched, 150 mm loft insulation", + "Pitched, 175 mm loft insulation", + "Pitched, 200 mm loft insulation", + "Pitched, 225 mm loft insulation", + "Pitched, 250 mm loft insulation", + "Pitched, 270 mm loft insulation", + "Pitched, 300 mm loft insulation", + "Pitched, 350 mm loft insulation", + "Pitched, 400 mm loft insulation", + "Pitched, 400+ mm loft insulation", + "Pitched, sloping ceiling, as built", + "Pitched, sloping ceiling, 12 mm insulation", + "Pitched, sloping ceiling, 25 mm insulation", + "Pitched, sloping ceiling, 50 mm insulation", + "Pitched, sloping ceiling, 75 mm insulation", + "Pitched, sloping ceiling, 100 mm insulation", + "Pitched, sloping ceiling, 125 mm insulation", + "Pitched, sloping ceiling, 150 mm insulation", + "Pitched, sloping ceiling, 175 mm insulation", + "Pitched, sloping ceiling, 200 mm insulation", + "Pitched, sloping ceiling, 225 mm insulation", + "Pitched, sloping ceiling, 250 mm insulation", + "Pitched, sloping ceiling, 270 mm insulation", + "Pitched, sloping ceiling, 300 mm insulation", + "Pitched, sloping ceiling, 350 mm insulation", + "Pitched, sloping ceiling, 400 mm insulation", + "Pitched, sloping ceiling, 400+ mm insulation", + "Roof room(s), insulated", + "Roof room(s), insulated (assumed)", + "Roof room(s), limited insulation", + "Roof room(s), limited insulation (assumed)", + "Roof room(s), no insulation", + "Roof room(s), no insulation (assumed)", + "Roof room(s), ceiling insulated", + "Roof room(s), thatched", + "Roof room(s), thatched with additional insulation", + "Thatched", + "Thatched, with additional insulation", + "(another dwelling above)", + "(same dwelling above)", + "(other premises above)", + "(another premises above)", + "Another Premises Above", + "Unknown" + ] + }, + "public.wall_type": { + "name": "wall_type", + "schema": "public", + "values": [ + "Cavity wall, filled cavity", + "Cavity wall, as built, insulated (assumed)", + "Cavity wall, as built, no insulation (assumed)", + "Cavity wall, as built, partial insulation (assumed)", + "Cavity wall, with internal insulation", + "Cavity wall, with external insulation", + "Cavity wall, filled cavity and internal insulation", + "Cavity wall, filled cavity and external insulation", + "Solid brick, as built, no insulation (assumed)", + "Solid brick, as built, insulated (assumed)", + "Solid brick, as built, partial insulation (assumed)", + "Solid brick, with internal insulation", + "Solid brick, with external insulation", + "Timber frame, as built, no insulation (assumed)", + "Timber frame, as built, insulated (assumed)", + "Timber frame, as built, partial insulation (assumed)", + "Timber frame, with additional insulation", + "Sandstone, as built, no insulation (assumed)", + "Sandstone, as built, insulated (assumed)", + "Sandstone, as built, partial insulation (assumed)", + "Sandstone, with internal insulation", + "Sandstone, with external insulation", + "Granite or whin, as built, no insulation (assumed)", + "Granite or whin, as built, insulated (assumed)", + "Granite or whin, as built, partial insulation (assumed)", + "Granite or whin, with internal insulation", + "Granite or whin, with external insulation", + "System built, as built, no insulation (assumed)", + "System built, as built, insulated (assumed)", + "System built, as built, partial insulation (assumed)", + "System built, with internal insulation", + "System built, with external insulation", + "Park home wall, as built", + "Park home wall, with internal insulation", + "Park home wall, with external insulation", + "Cob, as built", + "Cob, with internal insulation", + "Cob, with external insulation", + "Curtain wall", + "Curtain Wall, as built, no insulation (assumed)", + "Curtain Wall, as built, insulated (assumed)", + "Curtain Wall, filled cavity", + "Curtain Wall, with internal insulation", + "Basement wall", + "Basement wall, as built", + "Unknown" + ] + }, + "public.water_heating": { + "name": "water_heating", + "schema": "public", + "values": [ + "From main system, mains gas", + "From main system, electricity", + "From main system, oil", + "From main system, LPG (bulk)", + "From main system, bottled LPG", + "From main system, house coal", + "Electric immersion, electricity", + "Gas boiler/circulator, mains gas", + "From main system, wood logs", + "From main system, biomass (community)", + "From main system, dual fuel (mineral and wood)", + "From main system, biodiesel (community)", + "Unknown" + ] + }, + "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", + "secondary_glazing", + "double_glazing", + "trickle_vent", + "door_undercut", + "solar_pv", + "solar_battery", + "scaffolding", + "high_heat_retention_storage_heaters", + "air_source_heat_pump", + "boiler_upgrade", + "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.portfolio_capability": { + "name": "portfolio_capability", + "schema": "public", + "values": [ + "approver", + "contractor" + ] + }, + "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.override_component": { + "name": "override_component", + "schema": "public", + "values": [ + "wall_type", + "roof_type", + "property_type", + "built_form_type", + "main_fuel", + "glazing", + "construction_age_band", + "water_heating", + "main_heating_system" + ] + }, + "public.energy_element_type": { + "name": "energy_element_type", + "schema": "public", + "values": [ + "roof", + "wall", + "floor", + "main_heating", + "window", + "lighting", + "hot_water", + "secondary_heating", + "main_heating_controls" + ] + }, + "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.rebaseline_reason": { + "name": "rebaseline_reason", + "schema": "public", + "values": [ + "none", + "pre_sap10", + "physical_state_changed", + "both" + ] + }, + "public.housing_type": { + "name": "housing_type", + "schema": "public", + "values": [ + "Private", + "Social" + ] + }, + "public.measure_type": { + "name": "measure_type", + "schema": "public", + "values": [ + "air_source_heat_pump", + "boiler_upgrade", + "high_heat_retention_storage_heaters", + "secondary_heating", + "roomstat_programmer_trvs", + "time_temperature_zone_control", + "cylinder_thermostat", + "cavity_wall_insulation", + "extension_cavity_wall_insulation", + "external_wall_insulation", + "internal_wall_insulation", + "loft_insulation", + "flat_roof_insulation", + "room_roof_insulation", + "solid_floor_insulation", + "suspended_floor_insulation", + "double_glazing", + "secondary_glazing", + "draught_proofing", + "mechanical_ventilation", + "low_energy_lighting", + "solar_pv", + "hot_water_tank_insulation", + "sealing_open_fireplace" + ] + }, + "public.plan_type": { + "name": "plan_type", + "schema": "public", + "values": [ + "solar_eco4", + "solar_hhrsh_eco4", + "empty_cavity_eco", + "partial_cavity_eco", + "extraction_eco" + ] + }, + "public.unit_quantity": { + "name": "unit_quantity", + "schema": "public", + "values": [ + "m2", + "part", + "kwp" + ] + }, + "public.scenario_type": { + "name": "scenario_type", + "schema": "public", + "values": [ + "unit", + "building" + ] + }, + "public.source": { + "name": "source", + "schema": "public", + "values": [ + "portfolio_id", + "hubspot_deal_id", + "property_id" + ] + }, + "public.file_source": { + "name": "file_source", + "schema": "public", + "values": [ + "pas hub", + "sharepoint", + "hubspot", + "ecmk", + "contractor", + "magic_plan", + "coordination_hub", + "audit_generator", + "projects" + ] + }, + "public.file_type": { + "name": "file_type", + "schema": "public", + "values": [ + "photo_pack", + "site_note", + "rd_sap_site_note", + "pas_2023_ventilation", + "pas_2023_condition", + "pas_significance", + "par_photo_pack", + "pas_2023_property", + "pas_2023_occupancy", + "ecmk_site_note", + "ecmk_rd_sap_site_note", + "ecmk_survey_xml", + "pre_photo", + "mid_photo", + "post_photo", + "loft_hatch_photo", + "dmev_photos", + "door_undercut_photos", + "trickle_vent_photos", + "pre_installation_building_inspection", + "point_of_work_risk_assessment", + "claim_of_compliance", + "mcs_compliance_certificate", + "certificate_of_conformity", + "minor_works_electrical_certificate", + "trustmark_licence_numbers", + "operative_competency", + "ventilation_assessment_checklist", + "anemometer_readings", + "commissioning_records", + "part_f_ventilation_document", + "handover_pack", + "insurance_guarantee", + "workmanship_warranty", + "g98_notification", + "installer_qualifications", + "installer_feedback", + "contractor_other", + "magic_plan_json", + "improvement_option_evaluation", + "medium_term_improvement_plan", + "retrofit_design_doc", + "ventilation_audit", + "other" + ] + }, + "public.user_defined_deal_measure_source": { + "name": "user_defined_deal_measure_source", + "schema": "public", + "values": [ + "instructed", + "pibi_ordered" + ] + }, + "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/0279_snapshot.json b/src/app/db/migrations/meta/0279_snapshot.json new file mode 100644 index 00000000..daa17d9a --- /dev/null +++ b/src/app/db/migrations/meta/0279_snapshot.json @@ -0,0 +1,13492 @@ +{ + "id": "ad5d3fd1-4e2e-428e-81e2-41c117e9d1e9", + "prevId": "587523ce-86b8-4329-b215-5ead69a0e951", + "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()" + }, + "last_updated_at": { + "name": "last_updated_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.deal_measure_approval_events": { + "name": "deal_measure_approval_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "acted_by": { + "name": "acted_by", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "acted_at": { + "name": "acted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_deal_measure_events_deal_id": { + "name": "idx_deal_measure_events_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_deal_measure_events_acted_at": { + "name": "idx_deal_measure_events_acted_at", + "columns": [ + { + "expression": "acted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deal_measure_approval_events_acted_by_user_id_fk": { + "name": "deal_measure_approval_events_acted_by_user_id_fk", + "tableFrom": "deal_measure_approval_events", + "tableTo": "user", + "columnsFrom": [ + "acted_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deal_measure_approvals": { + "name": "deal_measure_approvals", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_approved": { + "name": "is_approved", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "approved_by": { + "name": "approved_by", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "approved_at": { + "name": "approved_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_deal_measure_approvals_deal_id": { + "name": "idx_deal_measure_approvals_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deal_measure_approvals_approved_by_user_id_fk": { + "name": "deal_measure_approvals_approved_by_user_id_fk", + "tableFrom": "deal_measure_approvals", + "tableTo": "user", + "columnsFrom": [ + "approved_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "uq_deal_measure": { + "name": "uq_deal_measure", + "nullsNotDistinct": false, + "columns": [ + "hubspot_deal_id", + "measure_name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bulk_address_uploads": { + "name": "bulk_address_uploads", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "s3_bucket": { + "name": "s3_bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "s3_key": { + "name": "s3_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "filename": { + "name": "filename", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'ready_for_processing'" + }, + "source_headers": { + "name": "source_headers", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "column_mapping": { + "name": "column_mapping", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "multi_entry_summary": { + "name": "multi_entry_summary", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "multi_entry_ordering": { + "name": "multi_entry_ordering", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "verify_ack": { + "name": "verify_ack", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "task_id": { + "name": "task_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "combined_output_s3_uri": { + "name": "combined_output_s3_uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bulk_upload_uprn_corrections": { + "name": "bulk_upload_uprn_corrections", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "upload_id": { + "name": "upload_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "source_row_id": { + "name": "source_row_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address": { + "name": "address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "marked_no_uprn": { + "name": "marked_no_uprn", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "bulk_upload_uprn_corrections_upload_id_bulk_address_uploads_id_fk": { + "name": "bulk_upload_uprn_corrections_upload_id_bulk_address_uploads_id_fk", + "tableFrom": "bulk_upload_uprn_corrections", + "tableTo": "bulk_address_uploads", + "columnsFrom": [ + "upload_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "bulk_upload_uprn_corrections_upload_row_unique": { + "name": "bulk_upload_uprn_corrections_upload_row_unique", + "nullsNotDistinct": false, + "columns": [ + "upload_id", + "source_row_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.aspect_condition": { + "name": "aspect_condition", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "element_id": { + "name": "element_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "aspect_type": { + "name": "aspect_type", + "type": "aspect_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "aspect_instance": { + "name": "aspect_instance", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "quantity": { + "name": "quantity", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "install_date": { + "name": "install_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "renewal_year": { + "name": "renewal_year", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "comments": { + "name": "comments", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "aspect_condition_element_id_element_id_fk": { + "name": "aspect_condition_element_id_element_id_fk", + "tableFrom": "aspect_condition", + "tableTo": "element", + "columnsFrom": [ + "element_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.element": { + "name": "element", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "survey_id": { + "name": "survey_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "element_type": { + "name": "element_type", + "type": "element_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "element_instance": { + "name": "element_instance", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "element_survey_id_property_condition_survey_id_fk": { + "name": "element_survey_id_property_condition_survey_id_fk", + "tableFrom": "element", + "tableTo": "property_condition_survey", + "columnsFrom": [ + "survey_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_condition_survey": { + "name": "property_condition_survey", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "date": { + "name": "date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hubspot_company_data": { + "name": "hubspot_company_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "company_name": { + "name": "company_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "group_id": { + "name": "group_id", + "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": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hubspot_deal_data": { + "name": "hubspot_deal_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "deal_id": { + "name": "deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dealname": { + "name": "dealname", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dealstage": { + "name": "dealstage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "company_id": { + "name": "company_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "project_code": { + "name": "project_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "landlord_property_id": { + "name": "landlord_property_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "listing_id": { + "name": "listing_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uprn": { + "name": "uprn", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "outcome": { + "name": "outcome", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "outcome_notes": { + "name": "outcome_notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "major_condition_issue_description": { + "name": "major_condition_issue_description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "major_condition_issue_photos": { + "name": "major_condition_issue_photos", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "major_condition_issue_evidence_s3_url": { + "name": "major_condition_issue_evidence_s3_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "coordination_status": { + "name": "coordination_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "design_status": { + "name": "design_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "booking_status": { + "name": "booking_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pashub_link": { + "name": "pashub_link", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sharepoint_link": { + "name": "sharepoint_link", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dampmould_growth": { + "name": "dampmould_growth", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pre_sap": { + "name": "pre_sap", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "coordinator": { + "name": "coordinator", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mtp_completion_date": { + "name": "mtp_completion_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "mtp_re_model_completion_date": { + "name": "mtp_re_model_completion_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "ioe_v3_completion_date": { + "name": "ioe_v3_completion_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "proposed_measures": { + "name": "proposed_measures", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "approved_package": { + "name": "approved_package", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "designer": { + "name": "designer", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "design_type": { + "name": "design_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "design_completion_date": { + "name": "design_completion_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "actual_measures_installed": { + "name": "actual_measures_installed", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "installer": { + "name": "installer", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "installer_handover": { + "name": "installer_handover", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lodgement_status": { + "name": "lodgement_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "measures_lodgement_date": { + "name": "measures_lodgement_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "lodgement_date": { + "name": "lodgement_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "expected_commencement_date": { + "name": "expected_commencement_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "coordination_comments": { + "name": "coordination_comments", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "surveyor": { + "name": "surveyor", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "damp_mould_and_repairs_comments": { + "name": "damp_mould_and_repairs_comments", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "batch": { + "name": "batch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "batch_description": { + "name": "batch_description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "block_reference": { + "name": "block_reference", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "nonfunded_measures": { + "name": "nonfunded_measures", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_prn": { + "name": "epc_prn", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "potential_post_sap_score_dropdown": { + "name": "potential_post_sap_score_dropdown", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ei_score": { + "name": "ei_score", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ei_score__potential_": { + "name": "ei_score__potential_", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_sap_score": { + "name": "epc_sap_score", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_sap_score__potential_": { + "name": "epc_sap_score__potential_", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmed_survey_date": { + "name": "confirmed_survey_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "confirmed_survey_time": { + "name": "confirmed_survey_time", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "surveyed_date": { + "name": "surveyed_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "survey_type": { + "name": "survey_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "measures_for_pibi_ordered": { + "name": "measures_for_pibi_ordered", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pibi_order_date": { + "name": "pibi_order_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "pibi_completed_date": { + "name": "pibi_completed_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "property_halted_date": { + "name": "property_halted_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "property_halted_reason": { + "name": "property_halted_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "technical_approved_measures_for_install": { + "name": "technical_approved_measures_for_install", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sent_to_installer_for_pricing": { + "name": "sent_to_installer_for_pricing", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "domna_survey_required": { + "name": "domna_survey_required", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "domna_survey_type": { + "name": "domna_survey_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "domna_survey_date": { + "name": "domna_survey_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "date_booking_made": { + "name": "date_booking_made", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "last_contact_date": { + "name": "last_contact_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "last_outbound_call": { + "name": "last_outbound_call", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "last_outbound_email": { + "name": "last_outbound_email", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "last_submission_date": { + "name": "last_submission_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "number_of_attempts": { + "name": "number_of_attempts", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "client_booking_reference": { + "name": "client_booking_reference", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "third_party_surveyor_identifier": { + "name": "third_party_surveyor_identifier", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "design_constraints": { + "name": "design_constraints", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "planning_comments": { + "name": "planning_comments", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "planning_status": { + "name": "planning_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "planning_suggested_approach": { + "name": "planning_suggested_approach", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "planning_authority": { + "name": "planning_authority", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "designated_area": { + "name": "designated_area", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "article_4_pd_rights": { + "name": "article_4_pd_rights", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "listed_building": { + "name": "listed_building", + "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": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hubspot_projects_data": { + "name": "hubspot_projects_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "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": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "hubspot_projects_data_project_id_unique": { + "name": "hubspot_projects_data_project_id_unique", + "nullsNotDistinct": false, + "columns": [ + "project_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hubspot_users": { + "name": "hubspot_users", + "schema": "", + "columns": { + "hubspot_owner_id": { + "name": "hubspot_owner_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "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.epc_store": { + "name": "epc_store", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "epc_api_created_at": { + "name": "epc_api_created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "epc_api": { + "name": "epc_api", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "epc_page_created_at": { + "name": "epc_page_created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "epc_page": { + "name": "epc_page", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_page_rrn": { + "name": "epc_page_rrn", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "uq_epc_store_uprn": { + "name": "uq_epc_store_uprn", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.files_from_surveyor": { + "name": "files_from_surveyor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "s3_json_url": { + "name": "s3_json_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "files_from_surveyor_portfolio_id_portfolio_id_fk": { + "name": "files_from_surveyor_portfolio_id_portfolio_id_fk", + "tableFrom": "files_from_surveyor", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "files_from_surveyor_property_id_property_id_fk": { + "name": "files_from_surveyor_property_id_property_id_fk", + "tableFrom": "files_from_surveyor", + "tableTo": "property", + "columnsFrom": [ + "property_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.inspections": { + "name": "inspections", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "archetype": { + "name": "archetype", + "type": "inspection_archetype", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "archetype_2": { + "name": "archetype_2", + "type": "inspection_archetype_2", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "wall_construction": { + "name": "wall_construction", + "type": "inspections_wall_construction", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "insulation": { + "name": "insulation", + "type": "inspections_wall_insulation", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "insulation_material": { + "name": "insulation_material", + "type": "inspections_insulation_material", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "borescoped": { + "name": "borescoped", + "type": "inspection_borescoped", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "roof_orientation": { + "name": "roof_orientation", + "type": "inspections_roof_orientation", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "tile_hung": { + "name": "tile_hung", + "type": "inspections_tile_hung", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "rendered": { + "name": "rendered", + "type": "inspections_rendered", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "cladding": { + "name": "cladding", + "type": "inspections_cladding", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "access_issues": { + "name": "access_issues", + "type": "inspections_access_issues", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "surveyor_name": { + "name": "surveyor_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "inspections_property_id_property_id_fk": { + "name": "inspections_property_id_property_id_fk", + "tableFrom": "inspections", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_built_form_type_overrides": { + "name": "landlord_built_form_type_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "built_form_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_built_form_type_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_built_form_type_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_built_form_type_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_built_form_type_overrides_portfolio_description_unique": { + "name": "landlord_built_form_type_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_construction_age_band_overrides": { + "name": "landlord_construction_age_band_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "construction_age_band", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_construction_age_band_overrides_portfolio_fk": { + "name": "landlord_construction_age_band_overrides_portfolio_fk", + "tableFrom": "landlord_construction_age_band_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_construction_age_band_portfolio_description_unique": { + "name": "landlord_construction_age_band_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_glazing_overrides": { + "name": "landlord_glazing_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "glazing", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_glazing_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_glazing_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_glazing_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_glazing_overrides_portfolio_description_unique": { + "name": "landlord_glazing_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_main_fuel_overrides": { + "name": "landlord_main_fuel_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "main_fuel", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_main_fuel_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_main_fuel_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_main_fuel_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_main_fuel_overrides_portfolio_description_unique": { + "name": "landlord_main_fuel_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_main_heating_system_overrides": { + "name": "landlord_main_heating_system_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "main_heating_system", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_main_heating_system_overrides_portfolio_fk": { + "name": "landlord_main_heating_system_overrides_portfolio_fk", + "tableFrom": "landlord_main_heating_system_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_main_heating_system_portfolio_description_unique": { + "name": "landlord_main_heating_system_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_property_type_overrides": { + "name": "landlord_property_type_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "property_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_property_type_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_property_type_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_property_type_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_property_type_overrides_portfolio_description_unique": { + "name": "landlord_property_type_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_roof_type_overrides": { + "name": "landlord_roof_type_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "roof_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_roof_type_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_roof_type_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_roof_type_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_roof_type_overrides_portfolio_description_unique": { + "name": "landlord_roof_type_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_wall_type_overrides": { + "name": "landlord_wall_type_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "wall_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_wall_type_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_wall_type_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_wall_type_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_wall_type_overrides_portfolio_description_unique": { + "name": "landlord_wall_type_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_water_heating_overrides": { + "name": "landlord_water_heating_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "water_heating", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_water_heating_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_water_heating_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_water_heating_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_water_heating_overrides_portfolio_description_unique": { + "name": "landlord_water_heating_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_door_ventilation": { + "name": "magic_plan_door_ventilation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_door_id": { + "name": "magic_plan_door_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "undercut_mm": { + "name": "undercut_mm", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_door_ventilation_magic_plan_door_id_magic_plan_door_id_fk": { + "name": "magic_plan_door_ventilation_magic_plan_door_id_magic_plan_door_id_fk", + "tableFrom": "magic_plan_door_ventilation", + "tableTo": "magic_plan_door", + "columnsFrom": [ + "magic_plan_door_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "magic_plan_door_ventilation_magic_plan_door_id_unique": { + "name": "magic_plan_door_ventilation_magic_plan_door_id_unique", + "nullsNotDistinct": false, + "columns": [ + "magic_plan_door_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_door": { + "name": "magic_plan_door", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_room_id": { + "name": "magic_plan_room_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "width_mm": { + "name": "width_mm", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "height_mm": { + "name": "height_mm", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_door_magic_plan_room_id_magic_plan_room_id_fk": { + "name": "magic_plan_door_magic_plan_room_id_magic_plan_room_id_fk", + "tableFrom": "magic_plan_door", + "tableTo": "magic_plan_room", + "columnsFrom": [ + "magic_plan_room_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_floor": { + "name": "magic_plan_floor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_plan_id": { + "name": "magic_plan_plan_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "level": { + "name": "level", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_floor_magic_plan_plan_id_magic_plan_plan_id_fk": { + "name": "magic_plan_floor_magic_plan_plan_id_magic_plan_plan_id_fk", + "tableFrom": "magic_plan_floor", + "tableTo": "magic_plan_plan", + "columnsFrom": [ + "magic_plan_plan_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_plan": { + "name": "magic_plan_plan", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address": { + "name": "address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "magic_plan_uid": { + "name": "magic_plan_uid", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uploaded_file_id": { + "name": "uploaded_file_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_plan_uploaded_file_id_uploaded_files_id_fk": { + "name": "magic_plan_plan_uploaded_file_id_uploaded_files_id_fk", + "tableFrom": "magic_plan_plan", + "tableTo": "uploaded_files", + "columnsFrom": [ + "uploaded_file_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "magic_plan_plan_magic_plan_uid_unique": { + "name": "magic_plan_plan_magic_plan_uid_unique", + "nullsNotDistinct": false, + "columns": [ + "magic_plan_uid" + ] + }, + "magic_plan_plan_uploaded_file_id_unique": { + "name": "magic_plan_plan_uploaded_file_id_unique", + "nullsNotDistinct": false, + "columns": [ + "uploaded_file_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_room": { + "name": "magic_plan_room", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_floor_id": { + "name": "magic_plan_floor_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "width_m": { + "name": "width_m", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "length_m": { + "name": "length_m", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "area_m2": { + "name": "area_m2", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_room_magic_plan_floor_id_magic_plan_floor_id_fk": { + "name": "magic_plan_room_magic_plan_floor_id_magic_plan_floor_id_fk", + "tableFrom": "magic_plan_room", + "tableTo": "magic_plan_floor", + "columnsFrom": [ + "magic_plan_floor_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_window_ventilation": { + "name": "magic_plan_window_ventilation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_window_id": { + "name": "magic_plan_window_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "opening_type": { + "name": "opening_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "num_openings": { + "name": "num_openings", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "pct_openable": { + "name": "pct_openable", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "trickle_vent_area_mm2": { + "name": "trickle_vent_area_mm2", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "num_trickle_vents": { + "name": "num_trickle_vents", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_window_ventilation_magic_plan_window_id_magic_plan_window_id_fk": { + "name": "magic_plan_window_ventilation_magic_plan_window_id_magic_plan_window_id_fk", + "tableFrom": "magic_plan_window_ventilation", + "tableTo": "magic_plan_window", + "columnsFrom": [ + "magic_plan_window_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "magic_plan_window_ventilation_magic_plan_window_id_unique": { + "name": "magic_plan_window_ventilation_magic_plan_window_id_unique", + "nullsNotDistinct": false, + "columns": [ + "magic_plan_window_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_window": { + "name": "magic_plan_window", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_room_id": { + "name": "magic_plan_room_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "width_m": { + "name": "width_m", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "height_m": { + "name": "height_m", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "area_m2": { + "name": "area_m2", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_window_magic_plan_room_id_magic_plan_room_id_fk": { + "name": "magic_plan_window_magic_plan_room_id_magic_plan_room_id_fk", + "tableFrom": "magic_plan_window", + "tableTo": "magic_plan_room", + "columnsFrom": [ + "magic_plan_room_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": { + "idx_material_active": { + "name": "idx_material_active", + "columns": [ + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"material\".\"is_active\"", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organisation": { + "name": "organisation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "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()" + }, + "hubspot_company_id": { + "name": "hubspot_company_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pibi_requests": { + "name": "pibi_requests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "ordered_at": { + "name": "ordered_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "pushed_at": { + "name": "pushed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_pibi_requests_deal_id": { + "name": "idx_pibi_requests_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_pibi_requests_portfolio_id": { + "name": "idx_pibi_requests_portfolio_id", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pibi_requests_portfolio_id_portfolio_id_fk": { + "name": "pibi_requests_portfolio_id_portfolio_id_fk", + "tableFrom": "pibi_requests", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "pibi_requests_created_by_user_id_user_id_fk": { + "name": "pibi_requests_created_by_user_id_user_id_fk", + "tableFrom": "pibi_requests", + "tableTo": "user", + "columnsFrom": [ + "created_by_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.portfolio_organisation": { + "name": "portfolio_organisation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "organisation_id": { + "name": "organisation_id", + "type": "uuid", + "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": { + "portfolio_organisation_portfolio_id_portfolio_id_fk": { + "name": "portfolio_organisation_portfolio_id_portfolio_id_fk", + "tableFrom": "portfolio_organisation", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "portfolio_organisation_organisation_id_organisation_id_fk": { + "name": "portfolio_organisation_organisation_id_organisation_id_fk", + "tableFrom": "portfolio_organisation", + "tableTo": "organisation", + "columnsFrom": [ + "organisation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "portfolio_organisation_portfolio_id_organisation_id_unique": { + "name": "portfolio_organisation_portfolio_id_organisation_id_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "organisation_id" + ] + } + }, + "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.portfolio_capabilities": { + "name": "portfolio_capabilities", + "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 + }, + "capability": { + "name": "capability", + "type": "portfolio_capability", + "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": { + "portfolio_capabilities_user_id_user_id_fk": { + "name": "portfolio_capabilities_user_id_user_id_fk", + "tableFrom": "portfolio_capabilities", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "portfolio_capabilities_portfolio_id_portfolio_id_fk": { + "name": "portfolio_capabilities_portfolio_id_portfolio_id_fk", + "tableFrom": "portfolio_capabilities", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "portfolio_capabilities_user_id_portfolio_id_capability_unique": { + "name": "portfolio_capabilities_user_id_portfolio_id_capability_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "portfolio_id", + "capability" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.portfolioInvitations": { + "name": "portfolioInvitations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "invited_by_user_id": { + "name": "invited_by_user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "portfolioInvitations_portfolio_id_portfolio_id_fk": { + "name": "portfolioInvitations_portfolio_id_portfolio_id_fk", + "tableFrom": "portfolioInvitations", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "portfolioInvitations_invited_by_user_id_user_id_fk": { + "name": "portfolioInvitations_invited_by_user_id_user_id_fk", + "tableFrom": "portfolioInvitations", + "tableTo": "user", + "columnsFrom": [ + "invited_by_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "portfolio_invitations_portfolio_email_unique": { + "name": "portfolio_invitations_portfolio_email_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "email" + ] + } + }, + "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.project": { + "name": "project", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "organisation_id": { + "name": "organisation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "project_type_id": { + "name": "project_type_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start_date": { + "name": "start_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "end_date": { + "name": "end_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "domna_admin_access": { + "name": "domna_admin_access", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "sharepoint_base_url": { + "name": "sharepoint_base_url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "sharepoint_sub_folder_template": { + "name": "sharepoint_sub_folder_template", + "type": "varchar", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "project_organisation_id_organisation_id_fk": { + "name": "project_organisation_id_organisation_id_fk", + "tableFrom": "project", + "tableTo": "organisation", + "columnsFrom": [ + "organisation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_project_type_id_project_type_id_fk": { + "name": "project_project_type_id_project_type_id_fk", + "tableFrom": "project", + "tableTo": "project_type", + "columnsFrom": [ + "project_type_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_property": { + "name": "project_property", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "project_property_project_id_project_id_fk": { + "name": "project_property_project_id_project_id_fk", + "tableFrom": "project_property", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_property_property_id_property_id_fk": { + "name": "project_property_property_id_property_id_fk", + "tableFrom": "project_property", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "project_property_project_id_property_id_unique": { + "name": "project_property_project_id_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "project_id", + "property_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_type": { + "name": "project_type", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_workstream": { + "name": "project_workstream", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "workstream_id": { + "name": "workstream_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "current_stage_id": { + "name": "current_stage_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "project_workstream_project_id_project_id_fk": { + "name": "project_workstream_project_id_project_id_fk", + "tableFrom": "project_workstream", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_workstream_workstream_id_workstream_id_fk": { + "name": "project_workstream_workstream_id_workstream_id_fk", + "tableFrom": "project_workstream", + "tableTo": "workstream", + "columnsFrom": [ + "workstream_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_workstream_current_stage_id_project_workstream_stage_id_fk": { + "name": "project_workstream_current_stage_id_project_workstream_stage_id_fk", + "tableFrom": "project_workstream", + "tableTo": "project_workstream_stage", + "columnsFrom": [ + "current_stage_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_workstream_contractor": { + "name": "project_workstream_contractor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_workstream_id": { + "name": "project_workstream_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "organisation_id": { + "name": "organisation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "update_stages_permission": { + "name": "update_stages_permission", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "upload_documents_permission": { + "name": "upload_documents_permission", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "assigned_at": { + "name": "assigned_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "project_workstream_contractor_project_workstream_id_project_workstream_id_fk": { + "name": "project_workstream_contractor_project_workstream_id_project_workstream_id_fk", + "tableFrom": "project_workstream_contractor", + "tableTo": "project_workstream", + "columnsFrom": [ + "project_workstream_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_workstream_contractor_organisation_id_organisation_id_fk": { + "name": "project_workstream_contractor_organisation_id_organisation_id_fk", + "tableFrom": "project_workstream_contractor", + "tableTo": "organisation", + "columnsFrom": [ + "organisation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_workstream_evidence_requirement": { + "name": "project_workstream_evidence_requirement", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_workstream_id": { + "name": "project_workstream_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "file_type": { + "name": "file_type", + "type": "file_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "project_workstream_stage_id": { + "name": "project_workstream_stage_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "required": { + "name": "required", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "naming_rule": { + "name": "naming_rule", + "type": "varchar", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "project_workstream_evidence_requirement_project_workstream_id_project_workstream_id_fk": { + "name": "project_workstream_evidence_requirement_project_workstream_id_project_workstream_id_fk", + "tableFrom": "project_workstream_evidence_requirement", + "tableTo": "project_workstream", + "columnsFrom": [ + "project_workstream_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_workstream_evidence_requirement_project_workstream_stage_id_project_workstream_stage_id_fk": { + "name": "project_workstream_evidence_requirement_project_workstream_stage_id_project_workstream_stage_id_fk", + "tableFrom": "project_workstream_evidence_requirement", + "tableTo": "project_workstream_stage", + "columnsFrom": [ + "project_workstream_stage_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_workstream_stage": { + "name": "project_workstream_stage", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_workstream_id": { + "name": "project_workstream_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "start_date": { + "name": "start_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "due_date": { + "name": "due_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "last_updated": { + "name": "last_updated", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status_description": { + "name": "status_description", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "project_workstream_stage_project_workstream_id_project_workstream_id_fk": { + "name": "project_workstream_stage_project_workstream_id_project_workstream_id_fk", + "tableFrom": "project_workstream_stage", + "tableTo": "project_workstream", + "columnsFrom": [ + "project_workstream_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.work_order": { + "name": "work_order", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "reference": { + "name": "reference", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "project_workstream_contractor_id": { + "name": "project_workstream_contractor_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "project_workstream_stage_id": { + "name": "project_workstream_stage_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "forecast_end": { + "name": "forecast_end", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "priority": { + "name": "priority", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "work_order_project_workstream_contractor_id_project_workstream_contractor_id_fk": { + "name": "work_order_project_workstream_contractor_id_project_workstream_contractor_id_fk", + "tableFrom": "work_order", + "tableTo": "project_workstream_contractor", + "columnsFrom": [ + "project_workstream_contractor_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "work_order_property_id_property_id_fk": { + "name": "work_order_property_id_property_id_fk", + "tableFrom": "work_order", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "work_order_project_workstream_stage_id_project_workstream_stage_id_fk": { + "name": "work_order_project_workstream_stage_id_project_workstream_stage_id_fk", + "tableFrom": "work_order", + "tableTo": "project_workstream_stage", + "columnsFrom": [ + "project_workstream_stage_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "work_order_reference_unique": { + "name": "work_order_reference_unique", + "nullsNotDistinct": false, + "columns": [ + "reference" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workstream": { + "name": "workstream", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_overrides": { + "name": "property_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "building_part": { + "name": "building_part", + "type": "smallint", + "primaryKey": false, + "notNull": true + }, + "override_component": { + "name": "override_component", + "type": "override_component", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "override_value": { + "name": "override_value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "original_spreadsheet_description": { + "name": "original_spreadsheet_description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "property_overrides_property_id_property_id_fk": { + "name": "property_overrides_property_id_property_id_fk", + "tableFrom": "property_overrides", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "property_overrides_portfolio_id_portfolio_id_fk": { + "name": "property_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "property_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "property_overrides_property_component_part_unique": { + "name": "property_overrides_property_component_part_unique", + "nullsNotDistinct": false, + "columns": [ + "property_id", + "override_component", + "building_part" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_building_part": { + "name": "epc_building_part", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "construction_age_band": { + "name": "construction_age_band", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "wall_construction": { + "name": "wall_construction", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "wall_insulation_type": { + "name": "wall_insulation_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "wall_thickness_measured": { + "name": "wall_thickness_measured", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "party_wall_construction": { + "name": "party_wall_construction", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "building_part_number": { + "name": "building_part_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "wall_dry_lined": { + "name": "wall_dry_lined", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "wall_thickness_mm": { + "name": "wall_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "wall_insulation_thickness": { + "name": "wall_insulation_thickness", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "wall_insulation_thermal_conductivity": { + "name": "wall_insulation_thermal_conductivity", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "floor_heat_loss": { + "name": "floor_heat_loss", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "floor_insulation_thickness": { + "name": "floor_insulation_thickness", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "flat_roof_insulation_thickness": { + "name": "flat_roof_insulation_thickness", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "floor_type": { + "name": "floor_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "floor_construction_type": { + "name": "floor_construction_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "floor_insulation_type_str": { + "name": "floor_insulation_type_str", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "floor_u_value_known": { + "name": "floor_u_value_known", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "roof_construction": { + "name": "roof_construction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "roof_insulation_location": { + "name": "roof_insulation_location", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "roof_insulation_thickness": { + "name": "roof_insulation_thickness", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "rafter_insulation_thickness": { + "name": "rafter_insulation_thickness", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "roof_construction_type": { + "name": "roof_construction_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "curtain_wall_age": { + "name": "curtain_wall_age", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "wall_is_basement": { + "name": "wall_is_basement", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "wall_u_value": { + "name": "wall_u_value", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_area": { + "name": "alt_wall_1_area", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_dry_lined": { + "name": "alt_wall_1_dry_lined", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_construction": { + "name": "alt_wall_1_construction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_insulation_type": { + "name": "alt_wall_1_insulation_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_thickness_measured": { + "name": "alt_wall_1_thickness_measured", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_insulation_thickness": { + "name": "alt_wall_1_insulation_thickness", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_is_sheltered": { + "name": "alt_wall_1_is_sheltered", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_u_value": { + "name": "alt_wall_1_u_value", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_thickness_mm": { + "name": "alt_wall_1_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_is_basement": { + "name": "alt_wall_1_is_basement", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_area": { + "name": "alt_wall_2_area", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_dry_lined": { + "name": "alt_wall_2_dry_lined", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_construction": { + "name": "alt_wall_2_construction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_insulation_type": { + "name": "alt_wall_2_insulation_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_thickness_measured": { + "name": "alt_wall_2_thickness_measured", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_insulation_thickness": { + "name": "alt_wall_2_insulation_thickness", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_is_sheltered": { + "name": "alt_wall_2_is_sheltered", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_u_value": { + "name": "alt_wall_2_u_value", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_thickness_mm": { + "name": "alt_wall_2_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_is_basement": { + "name": "alt_wall_2_is_basement", + "type": "boolean", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "ix_epc_building_part_epc_property": { + "name": "ix_epc_building_part_epc_property", + "columns": [ + { + "expression": "epc_property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_building_part_epc_property_id_epc_property_id_fk": { + "name": "epc_building_part_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_building_part", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_energy_element": { + "name": "epc_energy_element", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "element_type": { + "name": "element_type", + "type": "energy_element_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "energy_efficiency_rating": { + "name": "energy_efficiency_rating", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "environmental_efficiency_rating": { + "name": "environmental_efficiency_rating", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "ix_epc_energy_element_epc_property": { + "name": "ix_epc_energy_element_epc_property", + "columns": [ + { + "expression": "epc_property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_energy_element_epc_property_id_epc_property_id_fk": { + "name": "epc_energy_element_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_energy_element", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_flat_details": { + "name": "epc_flat_details", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "level": { + "name": "level", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "top_storey": { + "name": "top_storey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "flat_location": { + "name": "flat_location", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "heat_loss_corridor": { + "name": "heat_loss_corridor", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "storey_count": { + "name": "storey_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "unheated_corridor_length_m": { + "name": "unheated_corridor_length_m", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_flat_details_epc_property_id_epc_property_id_fk": { + "name": "epc_flat_details_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_flat_details", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_flat_details_epc_property_id_unique": { + "name": "epc_flat_details_epc_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "epc_property_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_floor_dimension": { + "name": "epc_floor_dimension", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_building_part_id": { + "name": "epc_building_part_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "floor": { + "name": "floor", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "room_height_m": { + "name": "room_height_m", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "total_floor_area_m2": { + "name": "total_floor_area_m2", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "party_wall_length_m": { + "name": "party_wall_length_m", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "heat_loss_perimeter_m": { + "name": "heat_loss_perimeter_m", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "floor_insulation": { + "name": "floor_insulation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "floor_construction": { + "name": "floor_construction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "is_exposed_floor": { + "name": "is_exposed_floor", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_above_partially_heated_space": { + "name": "is_above_partially_heated_space", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "ix_epc_floor_dimension_building_part": { + "name": "ix_epc_floor_dimension_building_part", + "columns": [ + { + "expression": "epc_building_part_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_floor_dimension_epc_building_part_id_epc_building_part_id_fk": { + "name": "epc_floor_dimension_epc_building_part_id_epc_building_part_id_fk", + "tableFrom": "epc_floor_dimension", + "tableTo": "epc_building_part", + "columnsFrom": [ + "epc_building_part_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_main_heating_detail": { + "name": "epc_main_heating_detail", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "has_fghrs": { + "name": "has_fghrs", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "main_fuel_type": { + "name": "main_fuel_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "heat_emitter_type": { + "name": "heat_emitter_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "emitter_temperature": { + "name": "emitter_temperature", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "main_heating_control": { + "name": "main_heating_control", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "fan_flue_present": { + "name": "fan_flue_present", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "boiler_flue_type": { + "name": "boiler_flue_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "boiler_ignition_type": { + "name": "boiler_ignition_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "central_heating_pump_age": { + "name": "central_heating_pump_age", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "central_heating_pump_age_str": { + "name": "central_heating_pump_age_str", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "main_heating_index_number": { + "name": "main_heating_index_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "sap_main_heating_code": { + "name": "sap_main_heating_code", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "main_heating_number": { + "name": "main_heating_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "main_heating_category": { + "name": "main_heating_category", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "main_heating_fraction": { + "name": "main_heating_fraction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "main_heating_data_source": { + "name": "main_heating_data_source", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "condensing": { + "name": "condensing", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "weather_compensator": { + "name": "weather_compensator", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "community_heating_boiler_fuel_type": { + "name": "community_heating_boiler_fuel_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "community_heating_chp_fraction": { + "name": "community_heating_chp_fraction", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "ix_epc_main_heating_detail_epc_property": { + "name": "ix_epc_main_heating_detail_epc_property", + "columns": [ + { + "expression": "epc_property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_main_heating_detail_epc_property_id_epc_property_id_fk": { + "name": "epc_main_heating_detail_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_main_heating_detail", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_photovoltaic_array": { + "name": "epc_photovoltaic_array", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "array_index": { + "name": "array_index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "peak_power": { + "name": "peak_power", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "pitch": { + "name": "pitch", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "overshading": { + "name": "overshading", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "orientation": { + "name": "orientation", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_photovoltaic_array_epc_property_id_epc_property_id_fk": { + "name": "epc_photovoltaic_array_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_photovoltaic_array", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_property": { + "name": "epc_property", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "uploaded_file_id": { + "name": "uploaded_file_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'lodged'" + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "uprn_source": { + "name": "uprn_source", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "report_reference": { + "name": "report_reference", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "report_type": { + "name": "report_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "assessment_type": { + "name": "assessment_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sap_version": { + "name": "sap_version", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "schema_type": { + "name": "schema_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "schema_versions_original": { + "name": "schema_versions_original", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "calculation_software_version": { + "name": "calculation_software_version", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address_line_1": { + "name": "address_line_1", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "address_line_2": { + "name": "address_line_2", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "post_town": { + "name": "post_town", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "region_code": { + "name": "region_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "country_code": { + "name": "country_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "language_code": { + "name": "language_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dwelling_type": { + "name": "dwelling_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "property_type": { + "name": "property_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "built_form": { + "name": "built_form", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tenure": { + "name": "tenure", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "transaction_type": { + "name": "transaction_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "inspection_date": { + "name": "inspection_date", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "completion_date": { + "name": "completion_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "registration_date": { + "name": "registration_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "total_floor_area_m2": { + "name": "total_floor_area_m2", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "measurement_type": { + "name": "measurement_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "solar_water_heating": { + "name": "solar_water_heating", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "has_hot_water_cylinder": { + "name": "has_hot_water_cylinder", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "has_fixed_air_conditioning": { + "name": "has_fixed_air_conditioning", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "has_conservatory": { + "name": "has_conservatory", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "has_heated_separate_conservatory": { + "name": "has_heated_separate_conservatory", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "conservatory_type": { + "name": "conservatory_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "conservatory_floor_area_m2": { + "name": "conservatory_floor_area_m2", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "conservatory_glazed_perimeter_m": { + "name": "conservatory_glazed_perimeter_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "conservatory_double_glazed": { + "name": "conservatory_double_glazed", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "conservatory_thermally_separated": { + "name": "conservatory_thermally_separated", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "conservatory_room_height_storeys": { + "name": "conservatory_room_height_storeys", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "door_count": { + "name": "door_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "wet_rooms_count": { + "name": "wet_rooms_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "extensions_count": { + "name": "extensions_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "heated_rooms_count": { + "name": "heated_rooms_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "open_chimneys_count": { + "name": "open_chimneys_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "habitable_rooms_count": { + "name": "habitable_rooms_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "insulated_door_count": { + "name": "insulated_door_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "cfl_fixed_lighting_bulbs_count": { + "name": "cfl_fixed_lighting_bulbs_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "led_fixed_lighting_bulbs_count": { + "name": "led_fixed_lighting_bulbs_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "incandescent_fixed_lighting_bulbs_count": { + "name": "incandescent_fixed_lighting_bulbs_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "blocked_chimneys_count": { + "name": "blocked_chimneys_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "draughtproofed_door_count": { + "name": "draughtproofed_door_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "energy_rating_average": { + "name": "energy_rating_average", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "low_energy_fixed_lighting_bulbs_count": { + "name": "low_energy_fixed_lighting_bulbs_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "fixed_lighting_outlets_count": { + "name": "fixed_lighting_outlets_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "low_energy_fixed_lighting_outlets_count": { + "name": "low_energy_fixed_lighting_outlets_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "number_of_storeys": { + "name": "number_of_storeys", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "any_unheated_rooms": { + "name": "any_unheated_rooms", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "hydro": { + "name": "hydro", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "photovoltaic_array": { + "name": "photovoltaic_array", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "waste_water_heat_recovery": { + "name": "waste_water_heat_recovery", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pressure_test": { + "name": "pressure_test", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "pressure_test_certificate_number": { + "name": "pressure_test_certificate_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "percent_draughtproofed": { + "name": "percent_draughtproofed", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "insulated_door_u_value": { + "name": "insulated_door_u_value", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "multiple_glazed_proportion": { + "name": "multiple_glazed_proportion", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "windows_transmission_u_value": { + "name": "windows_transmission_u_value", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "windows_transmission_data_source": { + "name": "windows_transmission_data_source", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "windows_transmission_solar_transmittance": { + "name": "windows_transmission_solar_transmittance", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_gas_connection_available": { + "name": "energy_gas_connection_available", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "energy_meter_type": { + "name": "energy_meter_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "energy_pv_battery_count": { + "name": "energy_pv_battery_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "energy_wind_turbines_count": { + "name": "energy_wind_turbines_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "energy_gas_smart_meter_present": { + "name": "energy_gas_smart_meter_present", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "energy_is_dwelling_export_capable": { + "name": "energy_is_dwelling_export_capable", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "energy_wind_turbines_terrain_type": { + "name": "energy_wind_turbines_terrain_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "energy_electricity_smart_meter_present": { + "name": "energy_electricity_smart_meter_present", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "energy_pv_connection": { + "name": "energy_pv_connection", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "energy_pv_percent_roof_area": { + "name": "energy_pv_percent_roof_area", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "energy_pv_battery_capacity": { + "name": "energy_pv_battery_capacity", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_wind_turbine_hub_height": { + "name": "energy_wind_turbine_hub_height", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_wind_turbine_rotor_diameter": { + "name": "energy_wind_turbine_rotor_diameter", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_pv_diverter_present": { + "name": "energy_pv_diverter_present", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "heating_cylinder_size": { + "name": "heating_cylinder_size", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_water_heating_code": { + "name": "heating_water_heating_code", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_water_heating_fuel": { + "name": "heating_water_heating_fuel", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_immersion_heating_type": { + "name": "heating_immersion_heating_type", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_insulation_type": { + "name": "heating_cylinder_insulation_type", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_thermostat": { + "name": "heating_cylinder_thermostat", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "heating_secondary_fuel_type": { + "name": "heating_secondary_fuel_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_secondary_heating_type": { + "name": "heating_secondary_heating_type", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_insulation_thickness_mm": { + "name": "heating_cylinder_insulation_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_volume_measured_l": { + "name": "heating_cylinder_volume_measured_l", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_heat_loss": { + "name": "heating_cylinder_heat_loss", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "heating_wwhrs_index_number_1": { + "name": "heating_wwhrs_index_number_1", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_wwhrs_index_number_2": { + "name": "heating_wwhrs_index_number_2", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_shower_outlet_type": { + "name": "heating_shower_outlet_type", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_shower_wwhrs": { + "name": "heating_shower_wwhrs", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_type": { + "name": "ventilation_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ventilation_draught_lobby": { + "name": "ventilation_draught_lobby", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "ventilation_pressure_test": { + "name": "ventilation_pressure_test", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ventilation_open_flues_count": { + "name": "ventilation_open_flues_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_closed_flues_count": { + "name": "ventilation_closed_flues_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_boiler_flues_count": { + "name": "ventilation_boiler_flues_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_other_flues_count": { + "name": "ventilation_other_flues_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_extract_fans_count": { + "name": "ventilation_extract_fans_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_passive_vents_count": { + "name": "ventilation_passive_vents_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_flueless_gas_fires_count": { + "name": "ventilation_flueless_gas_fires_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_in_pcdf_database": { + "name": "ventilation_in_pcdf_database", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "mechanical_ventilation": { + "name": "mechanical_ventilation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_duct_type": { + "name": "mechanical_vent_duct_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_duct_placement": { + "name": "mechanical_vent_duct_placement", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_duct_insulation": { + "name": "mechanical_vent_duct_insulation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_ventilation_index_number": { + "name": "mechanical_ventilation_index_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_measured_installation": { + "name": "mechanical_vent_measured_installation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_duct_insulation_level": { + "name": "mechanical_vent_duct_insulation_level", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "addendum_stone_walls": { + "name": "addendum_stone_walls", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "addendum_system_build": { + "name": "addendum_system_build", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "addendum_numbers": { + "name": "addendum_numbers", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_number_baths": { + "name": "heating_number_baths", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_number_baths_wwhrs": { + "name": "heating_number_baths_wwhrs", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_electric_shower_count": { + "name": "heating_electric_shower_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_mixer_shower_count": { + "name": "heating_mixer_shower_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_present": { + "name": "ventilation_present", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "ventilation_sheltered_sides": { + "name": "ventilation_sheltered_sides", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_has_suspended_timber_floor": { + "name": "ventilation_has_suspended_timber_floor", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "ventilation_suspended_timber_floor_sealed": { + "name": "ventilation_suspended_timber_floor_sealed", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "ventilation_has_draught_lobby": { + "name": "ventilation_has_draught_lobby", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "ventilation_air_permeability_ap4_m3_h_m2": { + "name": "ventilation_air_permeability_ap4_m3_h_m2", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "ventilation_air_permeability_ap50_m3_h_m2": { + "name": "ventilation_air_permeability_ap50_m3_h_m2", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "ventilation_mechanical_ventilation_kind": { + "name": "ventilation_mechanical_ventilation_kind", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "uq_epc_property_property_portfolio": { + "name": "uq_epc_property_property_portfolio", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "ix_epc_property_property_source": { + "name": "ix_epc_property_property_source", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_property_property_id_property_id_fk": { + "name": "epc_property_property_id_property_id_fk", + "tableFrom": "epc_property", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "epc_property_portfolio_id_portfolio_id_fk": { + "name": "epc_property_portfolio_id_portfolio_id_fk", + "tableFrom": "epc_property", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "epc_property_uploaded_file_id_uploaded_files_id_fk": { + "name": "epc_property_uploaded_file_id_uploaded_files_id_fk", + "tableFrom": "epc_property", + "tableTo": "uploaded_files", + "columnsFrom": [ + "uploaded_file_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_property_uploaded_file_id_unique": { + "name": "epc_property_uploaded_file_id_unique", + "nullsNotDistinct": false, + "columns": [ + "uploaded_file_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_property_energy_performance": { + "name": "epc_property_energy_performance", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "energy_rating_current": { + "name": "energy_rating_current", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "energy_consumption_current": { + "name": "energy_consumption_current", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "environmental_impact_current": { + "name": "environmental_impact_current", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_cost_current": { + "name": "heating_cost_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lighting_cost_current": { + "name": "lighting_cost_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "hot_water_cost_current": { + "name": "hot_water_cost_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_emissions_current": { + "name": "co2_emissions_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_emissions_current_per_floor_area": { + "name": "co2_emissions_current_per_floor_area", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "current_energy_efficiency_band": { + "name": "current_energy_efficiency_band", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "energy_rating_potential": { + "name": "energy_rating_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_consumption_potential": { + "name": "energy_consumption_potential", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "environmental_impact_potential": { + "name": "environmental_impact_potential", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_cost_potential": { + "name": "heating_cost_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lighting_cost_potential": { + "name": "lighting_cost_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "hot_water_cost_potential": { + "name": "hot_water_cost_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_emissions_potential": { + "name": "co2_emissions_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "potential_energy_efficiency_band": { + "name": "potential_energy_efficiency_band", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_property_energy_performance_epc_property_id_epc_property_id_fk": { + "name": "epc_property_energy_performance_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_property_energy_performance", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_property_energy_performance_epc_property_id_unique": { + "name": "epc_property_energy_performance_epc_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "epc_property_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_renewable_heat_incentive": { + "name": "epc_renewable_heat_incentive", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "space_heating_kwh": { + "name": "space_heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "water_heating_kwh": { + "name": "water_heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "impact_of_loft_insulation_kwh": { + "name": "impact_of_loft_insulation_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "impact_of_cavity_insulation_kwh": { + "name": "impact_of_cavity_insulation_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "impact_of_solid_wall_insulation_kwh": { + "name": "impact_of_solid_wall_insulation_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_renewable_heat_incentive_epc_property_id_epc_property_id_fk": { + "name": "epc_renewable_heat_incentive_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_renewable_heat_incentive", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_renewable_heat_incentive_epc_property_id_unique": { + "name": "epc_renewable_heat_incentive_epc_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "epc_property_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_roof_window": { + "name": "epc_roof_window", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "roof_window_index": { + "name": "roof_window_index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "area_m2": { + "name": "area_m2", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "u_value_raw": { + "name": "u_value_raw", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "orientation": { + "name": "orientation", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "pitch_deg": { + "name": "pitch_deg", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "g_perpendicular": { + "name": "g_perpendicular", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "frame_factor": { + "name": "frame_factor", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "glazing_type": { + "name": "glazing_type", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "window_location": { + "name": "window_location", + "type": "jsonb", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "uq_epc_roof_window_property_index": { + "name": "uq_epc_roof_window_property_index", + "columns": [ + { + "expression": "epc_property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "roof_window_index", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_roof_window_epc_property_id_epc_property_id_fk": { + "name": "epc_roof_window_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_roof_window", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_room_in_roof": { + "name": "epc_room_in_roof", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_building_part_id": { + "name": "epc_building_part_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "floor_area": { + "name": "floor_area", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "construction_age_band": { + "name": "construction_age_band", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "common_wall_length_m": { + "name": "common_wall_length_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "common_wall_height_m": { + "name": "common_wall_height_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "gable_1_length_m": { + "name": "gable_1_length_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "gable_1_height_m": { + "name": "gable_1_height_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "gable_2_length_m": { + "name": "gable_2_length_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "gable_2_height_m": { + "name": "gable_2_height_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_room_in_roof_epc_building_part_id_epc_building_part_id_fk": { + "name": "epc_room_in_roof_epc_building_part_id_epc_building_part_id_fk", + "tableFrom": "epc_room_in_roof", + "tableTo": "epc_building_part", + "columnsFrom": [ + "epc_building_part_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_room_in_roof_epc_building_part_id_unique": { + "name": "epc_room_in_roof_epc_building_part_id_unique", + "nullsNotDistinct": false, + "columns": [ + "epc_building_part_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_room_in_roof_surface": { + "name": "epc_room_in_roof_surface", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_room_in_roof_id": { + "name": "epc_room_in_roof_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "surface_index": { + "name": "surface_index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "area_m2": { + "name": "area_m2", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "insulation_thickness_mm": { + "name": "insulation_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "insulation_type": { + "name": "insulation_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "u_value": { + "name": "u_value", + "type": "double precision", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "uq_epc_room_in_roof_surface_index": { + "name": "uq_epc_room_in_roof_surface_index", + "columns": [ + { + "expression": "epc_room_in_roof_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "surface_index", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_room_in_roof_surface_epc_room_in_roof_id_epc_room_in_roof_id_fk": { + "name": "epc_room_in_roof_surface_epc_room_in_roof_id_epc_room_in_roof_id_fk", + "tableFrom": "epc_room_in_roof_surface", + "tableTo": "epc_room_in_roof", + "columnsFrom": [ + "epc_room_in_roof_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_window": { + "name": "epc_window", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "glazing_gap": { + "name": "glazing_gap", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "orientation": { + "name": "orientation", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "window_type": { + "name": "window_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "glazing_type": { + "name": "glazing_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "window_width": { + "name": "window_width", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "window_height": { + "name": "window_height", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "draught_proofed": { + "name": "draught_proofed", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "window_location": { + "name": "window_location", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "window_wall_type": { + "name": "window_wall_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "permanent_shutters_present": { + "name": "permanent_shutters_present", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "frame_material": { + "name": "frame_material", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "frame_factor": { + "name": "frame_factor", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "permanent_shutters_insulated": { + "name": "permanent_shutters_insulated", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "transmission_u_value": { + "name": "transmission_u_value", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "transmission_data_source": { + "name": "transmission_data_source", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "transmission_solar_transmittance": { + "name": "transmission_solar_transmittance", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_window_epc_property_id_epc_property_id_fk": { + "name": "epc_window_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_window", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_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 + }, + "certificate_number": { + "name": "certificate_number", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "landlord_property_id": { + "name": "landlord_property_id", + "type": "text", + "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 + }, + "user_inputted_address": { + "name": "user_inputted_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_inputted_postcode": { + "name": "user_inputted_postcode", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lexiscore": { + "name": "lexiscore", + "type": "real", + "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 + }, + "installed_measures_sap_point_adjustment": { + "name": "installed_measures_sap_point_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "is_sap_points_adjusted_for_installed_measures": { + "name": "is_sap_points_adjusted_for_installed_measures", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "original_sap_points": { + "name": "original_sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lodged_sap_points": { + "name": "lodged_sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lodged_epc_rating": { + "name": "lodged_epc_rating", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "marked_for_deletion": { + "name": "marked_for_deletion", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "uq_property_portfolio_uprn": { + "name": "uq_property_portfolio_uprn", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"property\".\"uprn\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "ix_property_portfolio": { + "name": "ix_property_portfolio", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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_baseline_performance": { + "name": "property_baseline_performance", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "lodged_sap_score": { + "name": "lodged_sap_score", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "lodged_epc_band": { + "name": "lodged_epc_band", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "lodged_co2_emissions_t_per_yr": { + "name": "lodged_co2_emissions_t_per_yr", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lodged_primary_energy_intensity_kwh_per_m2_yr": { + "name": "lodged_primary_energy_intensity_kwh_per_m2_yr", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "effective_sap_score": { + "name": "effective_sap_score", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "effective_epc_band": { + "name": "effective_epc_band", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "effective_co2_emissions_t_per_yr": { + "name": "effective_co2_emissions_t_per_yr", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "effective_primary_energy_intensity_kwh_per_m2_yr": { + "name": "effective_primary_energy_intensity_kwh_per_m2_yr", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "rebaseline_reason": { + "name": "rebaseline_reason", + "type": "rebaseline_reason", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "space_heating_kwh": { + "name": "space_heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "water_heating_kwh": { + "name": "water_heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "fuel_rates_period": { + "name": "fuel_rates_period", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "heating_kwh": { + "name": "heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "heating_cost_gbp": { + "name": "heating_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "hot_water_kwh": { + "name": "hot_water_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "hot_water_cost_gbp": { + "name": "hot_water_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lighting_kwh": { + "name": "lighting_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lighting_cost_gbp": { + "name": "lighting_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "appliances_kwh": { + "name": "appliances_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "appliances_cost_gbp": { + "name": "appliances_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cooking_kwh": { + "name": "cooking_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cooking_cost_gbp": { + "name": "cooking_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "pumps_fans_kwh": { + "name": "pumps_fans_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "pumps_fans_cost_gbp": { + "name": "pumps_fans_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cooling_kwh": { + "name": "cooling_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cooling_cost_gbp": { + "name": "cooling_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "standing_charges_gbp": { + "name": "standing_charges_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "seg_credit_gbp": { + "name": "seg_credit_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "total_annual_bill_gbp": { + "name": "total_annual_bill_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "property_baseline_performance_property_id_property_id_fk": { + "name": "property_baseline_performance_property_id_property_id_fk", + "tableFrom": "property_baseline_performance", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "property_baseline_performance_property_id_unique": { + "name": "property_baseline_performance_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "property_id" + ] + } + }, + "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 + }, + "lodgement_date": { + "name": "lodgement_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "is_expired": { + "name": "is_expired", + "type": "boolean", + "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 + }, + "sap_05_overwritten": { + "name": "sap_05_overwritten", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "sap_05_score": { + "name": "sap_05_score", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "sap_05_epc_rating": { + "name": "sap_05_epc_rating", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": 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 + }, + "original_co2_emissions": { + "name": "original_co2_emissions", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "original_primary_energy_consumption": { + "name": "original_primary_energy_consumption", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "original_current_energy_demand": { + "name": "original_current_energy_demand", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "original_current_energy_demand_heating_hotwater": { + "name": "original_current_energy_demand_heating_hotwater", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "installed_measures_co2_adjustment": { + "name": "installed_measures_co2_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "installed_measures_energy_demand_adjustment": { + "name": "installed_measures_energy_demand_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "installed_measures_total_energy_bill_adjustment": { + "name": "installed_measures_total_energy_bill_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "installed_measures_heat_demand_adjustment": { + "name": "installed_measures_heat_demand_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "is_epc_adjusted_for_installed_measures": { + "name": "is_epc_adjusted_for_installed_measures", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "lodged_co2_emissions": { + "name": "lodged_co2_emissions", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lodged_heat_demand": { + "name": "lodged_heat_demand", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "has_been_remodelled": { + "name": "has_been_remodelled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "environment_impact_current": { + "name": "environment_impact_current", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "uq_property_details_epc_property_portfolio": { + "name": "uq_property_details_epc_property_portfolio", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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": { + "uq_property_details_spatial_uprn": { + "name": "uq_property_details_spatial_uprn", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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.installed_measure": { + "name": "installed_measure", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "measure_type": { + "name": "measure_type", + "type": "measure_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "installed_at": { + "name": "installed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "sap_points": { + "name": "sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "carbon_savings": { + "name": "carbon_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "kwh_savings": { + "name": "kwh_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "bill_savings": { + "name": "bill_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "heat_demand_savings": { + "name": "heat_demand_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + } + }, + "indexes": { + "idx_installed_measure_uprn": { + "name": "idx_installed_measure_uprn", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_installed_measure_uprn_active": { + "name": "idx_installed_measure_uprn_active", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"installed_measure\".\"is_active\" = true", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_installed_measure_measure_type": { + "name": "idx_installed_measure_measure_type", + "columns": [ + { + "expression": "measure_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_installed_measure_uprn_measure": { + "name": "idx_installed_measure_uprn_measure", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "measure_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"installed_measure\".\"is_active\" = true", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "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 + }, + "post_sap_points": { + "name": "post_sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "post_epc_rating": { + "name": "post_epc_rating", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "post_co2_emissions": { + "name": "post_co2_emissions", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_savings": { + "name": "co2_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "post_energy_bill": { + "name": "post_energy_bill", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_bill_savings": { + "name": "energy_bill_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "post_energy_consumption": { + "name": "post_energy_consumption", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_consumption_savings": { + "name": "energy_consumption_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "valuation_post_retrofit": { + "name": "valuation_post_retrofit", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "valuation_increase": { + "name": "valuation_increase", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cost_of_works": { + "name": "cost_of_works", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "contingency_cost": { + "name": "contingency_cost", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "plan_type": { + "name": "plan_type", + "type": "plan_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_plan_portfolio_scenario": { + "name": "idx_plan_portfolio_scenario", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scenario_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_plan_latest_per_property": { + "name": "idx_plan_latest_per_property", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scenario_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_plan_property_default_latest": { + "name": "idx_plan_property_default_latest", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "where": "is_default = true", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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": { + "idx_plan_recommendations_plan_id": { + "name": "idx_plan_recommendations_plan_id", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_plan_recommendations_plan_rec": { + "name": "idx_plan_recommendations_plan_rec", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "recommendation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_plan_recommendations_recommendation_id": { + "name": "idx_plan_recommendations_recommendation_id", + "columns": [ + { + "expression": "recommendation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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 + }, + "plan_id": { + "name": "plan_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "material_id": { + "name": "material_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "material_quantity": { + "name": "material_quantity", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "material_quantity_unit": { + "name": "material_quantity_unit", + "type": "unit_quantity", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "material_depth": { + "name": "material_depth", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "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": { + "recommendation_property_id_idx": { + "name": "recommendation_property_id_idx", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_plan_id": { + "name": "idx_recommendation_plan_id", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_active_defaults": { + "name": "idx_recommendation_active_defaults", + "columns": [ + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"recommendation\".\"default\" = true AND \"recommendation\".\"already_installed\" = false", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_active_id_property": { + "name": "idx_recommendation_active_id_property", + "columns": [ + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"recommendation\".\"default\" = true AND \"recommendation\".\"already_installed\" = false", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_plan_default": { + "name": "idx_recommendation_plan_default", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "measure_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "estimated_cost", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"recommendation\".\"default\" = true AND \"recommendation\".\"already_installed\" = false", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_material_id": { + "name": "idx_recommendation_material_id", + "columns": [ + { + "expression": "material_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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" + }, + "recommendation_plan_id_plan_id_fk": { + "name": "recommendation_plan_id_plan_id_fk", + "tableFrom": "recommendation", + "tableTo": "plan", + "columnsFrom": [ + "plan_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "recommendation_material_id_material_id_fk": { + "name": "recommendation_material_id_material_id_fk", + "tableFrom": "recommendation", + "tableTo": "material", + "columnsFrom": [ + "material_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "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": { + "recommendation_materials_recommendation_id_idx": { + "name": "recommendation_materials_recommendation_id_idx", + "columns": [ + { + "expression": "recommendation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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": "cascade", + "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 + }, + "fabric_first": { + "name": "fabric_first", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "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.property_removal_requests": { + "name": "property_removal_requests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'removal'" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "requested_by": { + "name": "requested_by", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "requested_at": { + "name": "requested_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "reviewed_by": { + "name": "reviewed_by", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "reviewed_at": { + "name": "reviewed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "original_batch": { + "name": "original_batch", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_removal_requests_deal_id": { + "name": "idx_removal_requests_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_removal_requests_portfolio_id": { + "name": "idx_removal_requests_portfolio_id", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "property_removal_requests_portfolio_id_portfolio_id_fk": { + "name": "property_removal_requests_portfolio_id_portfolio_id_fk", + "tableFrom": "property_removal_requests", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "property_removal_requests_requested_by_user_id_fk": { + "name": "property_removal_requests_requested_by_user_id_fk", + "tableFrom": "property_removal_requests", + "tableTo": "user", + "columnsFrom": [ + "requested_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "property_removal_requests_reviewed_by_user_id_fk": { + "name": "property_removal_requests_reviewed_by_user_id_fk", + "tableFrom": "property_removal_requests", + "tableTo": "user", + "columnsFrom": [ + "reviewed_by" + ], + "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.survey_requests": { + "name": "survey_requests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "survey_type": { + "name": "survey_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "requested_by": { + "name": "requested_by", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "requested_at": { + "name": "requested_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "fulfilled_at": { + "name": "fulfilled_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_survey_requests_deal_id": { + "name": "idx_survey_requests_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_survey_requests_portfolio_id": { + "name": "idx_survey_requests_portfolio_id", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "survey_requests_portfolio_id_portfolio_id_fk": { + "name": "survey_requests_portfolio_id_portfolio_id_fk", + "tableFrom": "survey_requests", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "survey_requests_requested_by_user_id_fk": { + "name": "survey_requests_requested_by_user_id_fk", + "tableFrom": "survey_requests", + "tableTo": "user", + "columnsFrom": [ + "requested_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.portfolio_tag": { + "name": "portfolio_tag", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "colour": { + "name": "colour", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "uq_portfolio_tag_portfolio_lower_name": { + "name": "uq_portfolio_tag_portfolio_lower_name", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"name\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "portfolio_tag_portfolio_id_portfolio_id_fk": { + "name": "portfolio_tag_portfolio_id_portfolio_id_fk", + "tableFrom": "portfolio_tag", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_tag": { + "name": "property_tag", + "schema": "", + "columns": { + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "tag_id": { + "name": "tag_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "ix_property_tag_tag": { + "name": "ix_property_tag_tag", + "columns": [ + { + "expression": "tag_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "property_tag_property_id_property_id_fk": { + "name": "property_tag_property_id_property_id_fk", + "tableFrom": "property_tag", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "property_tag_tag_id_portfolio_tag_id_fk": { + "name": "property_tag_tag_id_portfolio_tag_id_fk", + "tableFrom": "property_tag", + "tableTo": "portfolio_tag", + "columnsFrom": [ + "tag_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "property_tag_property_id_tag_id_pk": { + "name": "property_tag_property_id_tag_id_pk", + "columns": [ + "property_id", + "tag_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sub_task": { + "name": "sub_task", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "task_id": { + "name": "task_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "job_started": { + "name": "job_started", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "job_completed": { + "name": "job_completed", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'In Progress'" + }, + "service": { + "name": "service", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "inputs": { + "name": "inputs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "outputs": { + "name": "outputs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cloud_logs_url": { + "name": "cloud_logs_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "sub_task_task_id_tasks_id_fk": { + "name": "sub_task_task_id_tasks_id_fk", + "tableFrom": "sub_task", + "tableTo": "tasks", + "columnsFrom": [ + "task_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tasks": { + "name": "tasks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "task_source": { + "name": "task_source", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "job_started": { + "name": "job_started", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "job_completed": { + "name": "job_completed", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'In Progress'" + }, + "service": { + "name": "service", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "source", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "source_id": { + "name": "source_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "inputs": { + "name": "inputs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team": { + "name": "team", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "uuid", + "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": { + "team_org_id_organisation_id_fk": { + "name": "team_org_id_organisation_id_fk", + "tableFrom": "team", + "tableTo": "organisation", + "columnsFrom": [ + "org_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_members": { + "name": "team_members", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "team_id": { + "name": "team_id", + "type": "uuid", + "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": { + "team_members_user_id_user_id_fk": { + "name": "team_members_user_id_user_id_fk", + "tableFrom": "team_members", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "team_members_team_id_team_id_fk": { + "name": "team_members_team_id_team_id_fk", + "tableFrom": "team_members", + "tableTo": "team", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_portfolio_permissions": { + "name": "team_portfolio_permissions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "team_id": { + "name": "team_id", + "type": "uuid", + "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": { + "team_portfolio_permissions_team_id_team_id_fk": { + "name": "team_portfolio_permissions_team_id_team_id_fk", + "tableFrom": "team_portfolio_permissions", + "tableTo": "team", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "team_portfolio_permissions_portfolio_id_portfolio_id_fk": { + "name": "team_portfolio_permissions_portfolio_id_portfolio_id_fk", + "tableFrom": "team_portfolio_permissions", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.uploaded_files": { + "name": "uploaded_files", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "s3_file_bucket": { + "name": "s3_file_bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "s3_file_key": { + "name": "s3_file_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "s3_upload_timestamp": { + "name": "s3_upload_timestamp", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "landlord_property_id": { + "name": "landlord_property_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "hubspot_listing_id": { + "name": "hubspot_listing_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "file_type": { + "name": "file_type", + "type": "file_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "file_source": { + "name": "file_source", + "type": "file_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uploaded_by": { + "name": "uploaded_by", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "work_order_id": { + "name": "work_order_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "project_workstream_evidence_requirement_id": { + "name": "project_workstream_evidence_requirement_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "uploaded_files_uploaded_by_user_id_fk": { + "name": "uploaded_files_uploaded_by_user_id_fk", + "tableFrom": "uploaded_files", + "tableTo": "user", + "columnsFrom": [ + "uploaded_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "uploaded_files_work_order_id_work_order_id_fk": { + "name": "uploaded_files_work_order_id_work_order_id_fk", + "tableFrom": "uploaded_files", + "tableTo": "work_order", + "columnsFrom": [ + "work_order_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "uploaded_files_project_workstream_evidence_requirement_id_project_workstream_evidence_requirement_id_fk": { + "name": "uploaded_files_project_workstream_evidence_requirement_id_project_workstream_evidence_requirement_id_fk", + "tableFrom": "uploaded_files", + "tableTo": "project_workstream_evidence_requirement", + "columnsFrom": [ + "project_workstream_evidence_requirement_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_defined_deal_measures": { + "name": "user_defined_deal_measures", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "user_defined_deal_measure_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "pushed_at": { + "name": "pushed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "confirmed_in_hubspot_at": { + "name": "confirmed_in_hubspot_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_user_defined_deal_measures_deal_id": { + "name": "idx_user_defined_deal_measures_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_user_defined_deal_measures_source": { + "name": "idx_user_defined_deal_measures_source", + "columns": [ + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_defined_deal_measures_created_by_user_id_user_id_fk": { + "name": "user_defined_deal_measures_created_by_user_id_user_id_fk", + "tableFrom": "user_defined_deal_measures", + "tableTo": "user", + "columnsFrom": [ + "created_by_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_portfolio_config": { + "name": "user_portfolio_config", + "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 + }, + "starred_at": { + "name": "starred_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "folder_id": { + "name": "folder_id", + "type": "bigint", + "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": { + "idx_user_portfolio_config_folder": { + "name": "idx_user_portfolio_config_folder", + "columns": [ + { + "expression": "folder_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_portfolio_config_user_id_user_id_fk": { + "name": "user_portfolio_config_user_id_user_id_fk", + "tableFrom": "user_portfolio_config", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_portfolio_config_portfolio_id_portfolio_id_fk": { + "name": "user_portfolio_config_portfolio_id_portfolio_id_fk", + "tableFrom": "user_portfolio_config", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_portfolio_config_folder_owner_fk": { + "name": "user_portfolio_config_folder_owner_fk", + "tableFrom": "user_portfolio_config", + "tableTo": "user_portfolio_folders", + "columnsFrom": [ + "folder_id", + "user_id" + ], + "columnsTo": [ + "id", + "user_id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_portfolio_config_user_portfolio_unique": { + "name": "user_portfolio_config_user_portfolio_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "portfolio_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_portfolio_folders": { + "name": "user_portfolio_folders", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "position": { + "name": "position", + "type": "integer", + "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": { + "idx_user_portfolio_folders_user_position": { + "name": "idx_user_portfolio_folders_user_position", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "position", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_portfolio_folders_user_id_user_id_fk": { + "name": "user_portfolio_folders_user_id_user_id_fk", + "tableFrom": "user_portfolio_folders", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_portfolio_folders_id_user_unique": { + "name": "user_portfolio_folders_id_user_unique", + "nullsNotDistinct": false, + "columns": [ + "id", + "user_id" + ] + } + }, + "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.authRateLimits": { + "name": "authRateLimits", + "schema": "", + "columns": { + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "count": { + "name": "count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "window_start": { + "name": "window_start", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "authRateLimits_scope_key_pk": { + "name": "authRateLimits_scope_key_pk", + "columns": [ + "scope", + "key" + ] + } + }, + "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 + }, + "code_hash": { + "name": "code_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.whlg": { + "name": "whlg", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.aspect_type": { + "name": "aspect_type", + "schema": "public", + "values": [ + "material", + "condition", + "type", + "area", + "configuration", + "presence", + "risk", + "severity", + "location", + "finish", + "insulation", + "pointing", + "spalling", + "lintels", + "cladding", + "category", + "quantity", + "adequacy", + "rating", + "strategy", + "extent", + "distribution", + "structure", + "covering", + "fire_rating", + "external_decoration", + "work_required", + "age_band", + "construction_type", + "classification", + "system" + ] + }, + "public.element_type": { + "name": "element_type", + "schema": "public", + "values": [ + "property", + "property_construction_type", + "property_classification", + "property_age_band", + "storey_count", + "floor_level", + "floor_level_front_door", + "accessible_housing_register", + "asbestos", + "quality_standard", + "ccu", + "passenger_lift", + "stairlift", + "disabled_hoist_tracking", + "disabled_facilities", + "steps_to_front_door", + "roof", + "pitched_roof_covering", + "flat_roof_covering", + "rainwater_goods", + "loft_insulation", + "porch_canopy", + "chimney", + "fascia", + "soffit", + "fascia_soffit_bargeboards", + "gutters", + "store_roof", + "garage_roof", + "garage_and_store_roof", + "external_wall", + "external_noise_insulation", + "primary_wall", + "secondary_wall", + "downpipes", + "external_decoration", + "cladding", + "spandrel_panels", + "garage_walls", + "party_wall_fire_break", + "external_brickwork_pointing", + "internal_downpipes_external_area", + "external_windows", + "communal_windows", + "secondary_glazing", + "store_windows", + "garage_windows", + "garage_and_store_windows", + "external_door", + "front_door", + "rear_door", + "store_door", + "garage_door", + "garage_and_store_door", + "communal_entrance_door", + "main_door", + "block_entrance_door", + "lintel", + "patio_french_door", + "door_entry_handset", + "paths_and_hardstandings", + "parking_areas", + "boundary_walls", + "front_fencing", + "rear_fencing", + "side_fencing", + "rear_gate", + "front_gate", + "gates", + "retaining_walls", + "private_balcony", + "balcony_balustrade", + "outbuildings", + "garage_structure", + "paving", + "roads", + "soil_and_vent", + "solar_thermals", + "drop_kerb", + "outbuilding_overhaul", + "external_structural_defects", + "access_ramp", + "kitchen", + "kitchen_space_layout", + "tenant_installed_kitchen", + "kitchen_extractor_fan", + "bathroom", + "secondary_bathroom", + "secondary_toilet", + "bathroom_extractor_fan", + "additional_wc_or_whb", + "bathroom_remaining_life_source", + "kitchen_remaining_life_source", + "central_heating", + "heating_boiler", + "heating_distribution", + "secondary_heating", + "hot_water_system", + "cold_water_storage", + "heating_system", + "boiler_fuel", + "water_heating", + "programmable_heating", + "community_heating", + "gas_available", + "heat_recovery_units", + "heating_improvements", + "electrical_wiring", + "consumer_unit", + "smoke_detection", + "heat_detection", + "carbon_monoxide_detection", + "fire_door_rating", + "fire_risk_assessment", + "internal_wiring", + "electrics", + "communal_heating", + "communal_boiler", + "communal_electrics", + "communal_fire_alarm", + "communal_emergency_lighting", + "communal_door_entry", + "communal_cctv", + "communal_bin_store", + "communal_bin_store_doors", + "communal_bin_store_walls", + "communal_bin_store_roof", + "communal_refuse_chute", + "communal_floor_covering", + "communal_kitchen", + "communal_bathroom", + "communal_toilets", + "communal_gates", + "communal_lift", + "communal_passenger_lift", + "communal_balcony_walkway", + "communal_entrance", + "communal_internal_decorations", + "communal_internal_floor", + "communal_walkways", + "communal_external_doors", + "communal_stairs", + "communal_aerial", + "communal_aov", + "communal_internal_doors", + "communal_lateral_mains", + "communal_lighting", + "communal_lighting_conductor", + "communal_store_roof", + "communal_store_walls", + "communal_store_doors", + "communal_warden_call_system", + "communal_bms", + "communal_booster_pump", + "communal_dry_riser", + "communal_wet_riser", + "communal_cold_water_storage", + "communal_sprinkler", + "communal_plug_sockets", + "communal_circulation_space", + "ffhh_damp", + "ffhh_hold_and_cold_water", + "ffhh_drainage_lavatories", + "ffhh_neglected", + "ffhh_natural_light", + "ffhh_ventilation", + "ffhh_food_prep_and_washup", + "ffhh_unsafe_layout", + "ffhh_unstable_building", + "hhsrs_damp_and_mould", + "hhsrs_excess_cold", + "hhsrs_excess_heat", + "hhsrs_asbestos_and_mmf", + "hhsrs_biocides", + "hhsrs_carbon_monoxide", + "hhsrs_lead", + "hhsrs_radiation", + "hhsrs_uncombusted_fuel_gas", + "hhsrs_volatile_organic_compounds", + "hhsrs_crowding_and_space", + "hhsrs_entry_by_intruders", + "hhsrs_lighting", + "hhsrs_noise", + "hhsrs_domestic_hygiene_pests_refuse", + "hhsrs_food_safety", + "hhsrs_personal_hygiene_sanitation", + "hhsrs_water_supply", + "hhsrs_falls_associated_with_baths", + "hhsrs_falls_on_level_surfaces", + "hhsrs_falls_on_stairs", + "hhsrs_falls_between_levels", + "hhsrs_electrical_hazards", + "hhsrs_fire", + "hhsrs_flames_hot_surfaces", + "hhsrs_collision_and_entrapment", + "hhsrs_collision_hazards_low_headroom", + "hhsrs_explosions", + "hhsrs_ergonomics", + "hhsrs_structural_collapse", + "hhsrs_amenities" + ] + }, + "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.inspection_archetype_2": { + "name": "inspection_archetype_2", + "schema": "public", + "values": [ + "detached", + "mid-terrace", + "enclosed mid-terrace", + "end-terrace", + "enclosed end-terrace", + "semi-detached" + ] + }, + "public.inspection_archetype": { + "name": "inspection_archetype", + "schema": "public", + "values": [ + "Bungalow", + "Flat", + "Maisonette", + "House", + "non-domestic" + ] + }, + "public.inspection_borescoped": { + "name": "inspection_borescoped", + "schema": "public", + "values": [ + "yes", + "no", + "refused" + ] + }, + "public.inspections_access_issues": { + "name": "inspections_access_issues", + "schema": "public", + "values": [ + "see notes", + "damp issues", + "foliage on walls", + "bushes against wall", + "trees around/anove property", + "high rise block flats/maisonettes", + "conservatory", + "lean-to", + "garage", + "extension", + "decking", + "shed against wall" + ] + }, + "public.inspections_cladding": { + "name": "inspections_cladding", + "schema": "public", + "values": [ + "none", + "cladded with “sufficient space to fill the wall”", + "cladded with “insufficient space to fill the wall”" + ] + }, + "public.inspections_insulation_material": { + "name": "inspections_insulation_material", + "schema": "public", + "values": [ + "empty 50-90", + "empty 100+", + "empty 30-40", + "empty less than 30", + "loose fibre/wool", + "eps/celo/king", + "fibre batts - with cavity", + "fibre batts - no cavity", + "loose bead", + "glued bead", + "formaldehyde", + "bubble wrap", + "poly chunks" + ] + }, + "public.inspections_rendered": { + "name": "inspections_rendered", + "schema": "public", + "values": [ + "no render", + "rendered with “insufficient” space between dpc and render", + "rendered with “sufficient” space between dpc and render" + ] + }, + "public.inspections_roof_orientation": { + "name": "inspections_roof_orientation", + "schema": "public", + "values": [ + "north", + "east", + "south", + "west", + "north-east", + "north-west", + "south-east", + "south-west", + "n/s split", + "e/w split", + "ne/sw split", + "nw/se split", + "flat roof", + "no roof", + "roof too small", + "already has solar pv" + ] + }, + "public.inspections_tile_hung": { + "name": "inspections_tile_hung", + "schema": "public", + "values": [ + "yes", + "no", + "first floor flats are tile hung" + ] + }, + "public.inspections_wall_construction": { + "name": "inspections_wall_construction", + "schema": "public", + "values": [ + "cavity", + "solid", + "system built", + "timber framed", + "steel framed", + "re-walled cavity", + "mansard pre-fab", + "mansard ewi", + "mansard re-walled" + ] + }, + "public.inspections_wall_insulation": { + "name": "inspections_wall_insulation", + "schema": "public", + "values": [ + "empty cavity", + "filled at build", + "partial", + "retro drilled", + "ewi", + "iwi", + "solid non-cavity", + "system built", + "timber framed", + "steel framed" + ] + }, + "public.built_form_type": { + "name": "built_form_type", + "schema": "public", + "values": [ + "Detached", + "Semi-Detached", + "Mid-Terrace", + "End-Terrace", + "Enclosed Mid-Terrace", + "Enclosed End-Terrace", + "Not Recorded", + "Unknown" + ] + }, + "public.construction_age_band": { + "name": "construction_age_band", + "schema": "public", + "values": [ + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "Unknown" + ] + }, + "public.glazing": { + "name": "glazing", + "schema": "public", + "values": [ + "Single glazing", + "Double glazing, 2002 or later", + "Double glazing, pre-2002", + "Triple glazing, pre-2002", + "Triple glazing, 2002 or later", + "Mixed glazing", + "Secondary glazing", + "Unknown" + ] + }, + "public.main_fuel": { + "name": "main_fuel", + "schema": "public", + "values": [ + "mains gas", + "mains gas (community)", + "electricity", + "electricity (community)", + "LPG (bulk)", + "bottled LPG", + "LPG special condition", + "oil", + "house coal", + "smokeless coal", + "dual fuel (mineral and wood)", + "biomass (community)", + "wood logs", + "Unknown" + ] + }, + "public.main_heating_system": { + "name": "main_heating_system", + "schema": "public", + "values": [ + "Gas boiler, combi", + "Gas boiler, regular", + "Gas CPSU", + "Oil boiler, regular", + "Oil boiler, combi", + "Solid fuel boiler", + "Electric storage heaters, old", + "Electric storage heaters, slimline", + "Electric storage heaters, convector", + "Electric storage heaters, fan", + "Direct-acting electric", + "Electric room heaters", + "Solid fuel room heater, closed", + "Air source heat pump", + "Community heating, boilers", + "Community heating, CHP and boilers", + "Oil room heater, 2000 or later", + "Gas room heater, condensing fire", + "Gas room heater, decorative fuel-effect", + "Gas room heater, flush live-effect", + "Gas room heater, open flue 1980 or later", + "Gas room heater, open flue pre-1980", + "Electric storage heaters, high heat retention", + "Solid fuel room heater, open fire", + "Solid fuel room heater, open fire with back boiler", + "Solid fuel room heater, closed with boiler", + "Electric boiler", + "Electric CPSU", + "Electric underfloor, in concrete slab (off-peak)", + "Electric underfloor, integrated storage and direct-acting", + "Electric underfloor, in screed above insulation", + "Unknown" + ] + }, + "public.override_source": { + "name": "override_source", + "schema": "public", + "values": [ + "classifier", + "user", + "os_places" + ] + }, + "public.property_type": { + "name": "property_type", + "schema": "public", + "values": [ + "House", + "Bungalow", + "Flat", + "Maisonette", + "Park home", + "Unknown" + ] + }, + "public.roof_type": { + "name": "roof_type", + "schema": "public", + "values": [ + "Flat, insulated", + "Flat, insulated (assumed)", + "Flat, limited insulation", + "Flat, limited insulation (assumed)", + "Flat, no insulation", + "Flat, no insulation (assumed)", + "Flat, 12 mm insulation", + "Flat, 25 mm insulation", + "Flat, 50 mm insulation", + "Flat, 75 mm insulation", + "Flat, 100 mm insulation", + "Flat, 125 mm insulation", + "Flat, 150 mm insulation", + "Flat, 175 mm insulation", + "Flat, 200 mm insulation", + "Flat, 225 mm insulation", + "Flat, 250 mm insulation", + "Flat, 270 mm insulation", + "Flat, 300 mm insulation", + "Flat, 350 mm insulation", + "Flat, 400 mm insulation", + "Flat, 400+ mm insulation", + "Pitched, insulated", + "Pitched, insulated (assumed)", + "Pitched, insulated at rafters", + "Pitched, limited insulation", + "Pitched, limited insulation (assumed)", + "Pitched, no insulation", + "Pitched, no insulation (assumed)", + "Pitched, Unknown loft insulation", + "Pitched, 0 mm loft insulation", + "Pitched, 12 mm loft insulation", + "Pitched, 25 mm loft insulation", + "Pitched, 50 mm loft insulation", + "Pitched, 75 mm loft insulation", + "Pitched, 100 mm loft insulation", + "Pitched, 125 mm loft insulation", + "Pitched, 150 mm loft insulation", + "Pitched, 175 mm loft insulation", + "Pitched, 200 mm loft insulation", + "Pitched, 225 mm loft insulation", + "Pitched, 250 mm loft insulation", + "Pitched, 270 mm loft insulation", + "Pitched, 300 mm loft insulation", + "Pitched, 350 mm loft insulation", + "Pitched, 400 mm loft insulation", + "Pitched, 400+ mm loft insulation", + "Pitched, sloping ceiling, as built", + "Pitched, sloping ceiling, 12 mm insulation", + "Pitched, sloping ceiling, 25 mm insulation", + "Pitched, sloping ceiling, 50 mm insulation", + "Pitched, sloping ceiling, 75 mm insulation", + "Pitched, sloping ceiling, 100 mm insulation", + "Pitched, sloping ceiling, 125 mm insulation", + "Pitched, sloping ceiling, 150 mm insulation", + "Pitched, sloping ceiling, 175 mm insulation", + "Pitched, sloping ceiling, 200 mm insulation", + "Pitched, sloping ceiling, 225 mm insulation", + "Pitched, sloping ceiling, 250 mm insulation", + "Pitched, sloping ceiling, 270 mm insulation", + "Pitched, sloping ceiling, 300 mm insulation", + "Pitched, sloping ceiling, 350 mm insulation", + "Pitched, sloping ceiling, 400 mm insulation", + "Pitched, sloping ceiling, 400+ mm insulation", + "Roof room(s), insulated", + "Roof room(s), insulated (assumed)", + "Roof room(s), limited insulation", + "Roof room(s), limited insulation (assumed)", + "Roof room(s), no insulation", + "Roof room(s), no insulation (assumed)", + "Roof room(s), ceiling insulated", + "Roof room(s), thatched", + "Roof room(s), thatched with additional insulation", + "Thatched", + "Thatched, with additional insulation", + "(another dwelling above)", + "(same dwelling above)", + "(other premises above)", + "(another premises above)", + "Another Premises Above", + "Unknown" + ] + }, + "public.wall_type": { + "name": "wall_type", + "schema": "public", + "values": [ + "Cavity wall, filled cavity", + "Cavity wall, as built, insulated (assumed)", + "Cavity wall, as built, no insulation (assumed)", + "Cavity wall, as built, partial insulation (assumed)", + "Cavity wall, with internal insulation", + "Cavity wall, with external insulation", + "Cavity wall, filled cavity and internal insulation", + "Cavity wall, filled cavity and external insulation", + "Solid brick, as built, no insulation (assumed)", + "Solid brick, as built, insulated (assumed)", + "Solid brick, as built, partial insulation (assumed)", + "Solid brick, with internal insulation", + "Solid brick, with external insulation", + "Timber frame, as built, no insulation (assumed)", + "Timber frame, as built, insulated (assumed)", + "Timber frame, as built, partial insulation (assumed)", + "Timber frame, with additional insulation", + "Sandstone, as built, no insulation (assumed)", + "Sandstone, as built, insulated (assumed)", + "Sandstone, as built, partial insulation (assumed)", + "Sandstone, with internal insulation", + "Sandstone, with external insulation", + "Granite or whin, as built, no insulation (assumed)", + "Granite or whin, as built, insulated (assumed)", + "Granite or whin, as built, partial insulation (assumed)", + "Granite or whin, with internal insulation", + "Granite or whin, with external insulation", + "System built, as built, no insulation (assumed)", + "System built, as built, insulated (assumed)", + "System built, as built, partial insulation (assumed)", + "System built, with internal insulation", + "System built, with external insulation", + "Park home wall, as built", + "Park home wall, with internal insulation", + "Park home wall, with external insulation", + "Cob, as built", + "Cob, with internal insulation", + "Cob, with external insulation", + "Curtain wall", + "Curtain Wall, as built, no insulation (assumed)", + "Curtain Wall, as built, insulated (assumed)", + "Curtain Wall, filled cavity", + "Curtain Wall, with internal insulation", + "Basement wall", + "Basement wall, as built", + "Unknown" + ] + }, + "public.water_heating": { + "name": "water_heating", + "schema": "public", + "values": [ + "From main system, mains gas", + "From main system, electricity", + "From main system, oil", + "From main system, LPG (bulk)", + "From main system, bottled LPG", + "From main system, house coal", + "Electric immersion, electricity", + "Gas boiler/circulator, mains gas", + "From main system, wood logs", + "From main system, biomass (community)", + "From main system, dual fuel (mineral and wood)", + "From main system, biodiesel (community)", + "Unknown" + ] + }, + "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", + "secondary_glazing", + "double_glazing", + "trickle_vent", + "door_undercut", + "solar_pv", + "solar_battery", + "scaffolding", + "high_heat_retention_storage_heaters", + "air_source_heat_pump", + "boiler_upgrade", + "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.portfolio_capability": { + "name": "portfolio_capability", + "schema": "public", + "values": [ + "approver", + "contractor" + ] + }, + "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.override_component": { + "name": "override_component", + "schema": "public", + "values": [ + "wall_type", + "roof_type", + "property_type", + "built_form_type", + "main_fuel", + "glazing", + "construction_age_band", + "water_heating", + "main_heating_system" + ] + }, + "public.energy_element_type": { + "name": "energy_element_type", + "schema": "public", + "values": [ + "roof", + "wall", + "floor", + "main_heating", + "window", + "lighting", + "hot_water", + "secondary_heating", + "main_heating_controls" + ] + }, + "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.rebaseline_reason": { + "name": "rebaseline_reason", + "schema": "public", + "values": [ + "none", + "pre_sap10", + "physical_state_changed", + "both" + ] + }, + "public.housing_type": { + "name": "housing_type", + "schema": "public", + "values": [ + "Private", + "Social" + ] + }, + "public.measure_type": { + "name": "measure_type", + "schema": "public", + "values": [ + "air_source_heat_pump", + "boiler_upgrade", + "high_heat_retention_storage_heaters", + "secondary_heating", + "roomstat_programmer_trvs", + "time_temperature_zone_control", + "cylinder_thermostat", + "cavity_wall_insulation", + "extension_cavity_wall_insulation", + "external_wall_insulation", + "internal_wall_insulation", + "loft_insulation", + "flat_roof_insulation", + "room_roof_insulation", + "solid_floor_insulation", + "suspended_floor_insulation", + "double_glazing", + "secondary_glazing", + "draught_proofing", + "mechanical_ventilation", + "low_energy_lighting", + "solar_pv", + "hot_water_tank_insulation", + "sealing_open_fireplace" + ] + }, + "public.plan_type": { + "name": "plan_type", + "schema": "public", + "values": [ + "solar_eco4", + "solar_hhrsh_eco4", + "empty_cavity_eco", + "partial_cavity_eco", + "extraction_eco" + ] + }, + "public.unit_quantity": { + "name": "unit_quantity", + "schema": "public", + "values": [ + "m2", + "part", + "kwp" + ] + }, + "public.scenario_type": { + "name": "scenario_type", + "schema": "public", + "values": [ + "unit", + "building" + ] + }, + "public.source": { + "name": "source", + "schema": "public", + "values": [ + "portfolio_id", + "hubspot_deal_id", + "property_id" + ] + }, + "public.file_source": { + "name": "file_source", + "schema": "public", + "values": [ + "pas hub", + "sharepoint", + "hubspot", + "ecmk", + "contractor", + "magic_plan", + "coordination_hub", + "audit_generator", + "projects" + ] + }, + "public.file_type": { + "name": "file_type", + "schema": "public", + "values": [ + "photo_pack", + "site_note", + "rd_sap_site_note", + "pas_2023_ventilation", + "pas_2023_condition", + "pas_significance", + "par_photo_pack", + "pas_2023_property", + "pas_2023_occupancy", + "ecmk_site_note", + "ecmk_rd_sap_site_note", + "ecmk_survey_xml", + "pre_photo", + "mid_photo", + "post_photo", + "loft_hatch_photo", + "dmev_photos", + "door_undercut_photos", + "trickle_vent_photos", + "pre_installation_building_inspection", + "point_of_work_risk_assessment", + "claim_of_compliance", + "mcs_compliance_certificate", + "certificate_of_conformity", + "minor_works_electrical_certificate", + "trustmark_licence_numbers", + "operative_competency", + "ventilation_assessment_checklist", + "anemometer_readings", + "commissioning_records", + "part_f_ventilation_document", + "handover_pack", + "insurance_guarantee", + "workmanship_warranty", + "g98_notification", + "installer_qualifications", + "installer_feedback", + "contractor_other", + "magic_plan_json", + "improvement_option_evaluation", + "medium_term_improvement_plan", + "retrofit_design_doc", + "ventilation_audit", + "other" + ] + }, + "public.user_defined_deal_measure_source": { + "name": "user_defined_deal_measure_source", + "schema": "public", + "values": [ + "instructed", + "pibi_ordered" + ] + }, + "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/0280_snapshot.json b/src/app/db/migrations/meta/0280_snapshot.json new file mode 100644 index 00000000..9ae7f8c9 --- /dev/null +++ b/src/app/db/migrations/meta/0280_snapshot.json @@ -0,0 +1,13493 @@ +{ + "id": "02e783cd-ab0a-4c15-b82c-dc26a43ffc0b", + "prevId": "ad5d3fd1-4e2e-428e-81e2-41c117e9d1e9", + "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()" + }, + "last_updated_at": { + "name": "last_updated_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.deal_measure_approval_events": { + "name": "deal_measure_approval_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "acted_by": { + "name": "acted_by", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "acted_at": { + "name": "acted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_deal_measure_events_deal_id": { + "name": "idx_deal_measure_events_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_deal_measure_events_acted_at": { + "name": "idx_deal_measure_events_acted_at", + "columns": [ + { + "expression": "acted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deal_measure_approval_events_acted_by_user_id_fk": { + "name": "deal_measure_approval_events_acted_by_user_id_fk", + "tableFrom": "deal_measure_approval_events", + "tableTo": "user", + "columnsFrom": [ + "acted_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deal_measure_approvals": { + "name": "deal_measure_approvals", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_approved": { + "name": "is_approved", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "approved_by": { + "name": "approved_by", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "approved_at": { + "name": "approved_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_deal_measure_approvals_deal_id": { + "name": "idx_deal_measure_approvals_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deal_measure_approvals_approved_by_user_id_fk": { + "name": "deal_measure_approvals_approved_by_user_id_fk", + "tableFrom": "deal_measure_approvals", + "tableTo": "user", + "columnsFrom": [ + "approved_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "uq_deal_measure": { + "name": "uq_deal_measure", + "nullsNotDistinct": false, + "columns": [ + "hubspot_deal_id", + "measure_name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bulk_address_uploads": { + "name": "bulk_address_uploads", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "s3_bucket": { + "name": "s3_bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "s3_key": { + "name": "s3_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "filename": { + "name": "filename", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'ready_for_processing'" + }, + "source_headers": { + "name": "source_headers", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "column_mapping": { + "name": "column_mapping", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "multi_entry_summary": { + "name": "multi_entry_summary", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "multi_entry_ordering": { + "name": "multi_entry_ordering", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "verify_ack": { + "name": "verify_ack", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "task_id": { + "name": "task_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "combined_output_s3_uri": { + "name": "combined_output_s3_uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bulk_upload_uprn_corrections": { + "name": "bulk_upload_uprn_corrections", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "upload_id": { + "name": "upload_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "source_row_id": { + "name": "source_row_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address": { + "name": "address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "marked_no_uprn": { + "name": "marked_no_uprn", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "bulk_upload_uprn_corrections_upload_id_bulk_address_uploads_id_fk": { + "name": "bulk_upload_uprn_corrections_upload_id_bulk_address_uploads_id_fk", + "tableFrom": "bulk_upload_uprn_corrections", + "tableTo": "bulk_address_uploads", + "columnsFrom": [ + "upload_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "bulk_upload_uprn_corrections_upload_row_unique": { + "name": "bulk_upload_uprn_corrections_upload_row_unique", + "nullsNotDistinct": false, + "columns": [ + "upload_id", + "source_row_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.aspect_condition": { + "name": "aspect_condition", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "element_id": { + "name": "element_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "aspect_type": { + "name": "aspect_type", + "type": "aspect_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "aspect_instance": { + "name": "aspect_instance", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "quantity": { + "name": "quantity", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "install_date": { + "name": "install_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "renewal_year": { + "name": "renewal_year", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "comments": { + "name": "comments", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "aspect_condition_element_id_element_id_fk": { + "name": "aspect_condition_element_id_element_id_fk", + "tableFrom": "aspect_condition", + "tableTo": "element", + "columnsFrom": [ + "element_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.element": { + "name": "element", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "survey_id": { + "name": "survey_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "element_type": { + "name": "element_type", + "type": "element_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "element_instance": { + "name": "element_instance", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "element_survey_id_property_condition_survey_id_fk": { + "name": "element_survey_id_property_condition_survey_id_fk", + "tableFrom": "element", + "tableTo": "property_condition_survey", + "columnsFrom": [ + "survey_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_condition_survey": { + "name": "property_condition_survey", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "date": { + "name": "date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hubspot_company_data": { + "name": "hubspot_company_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "company_id": { + "name": "company_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "company_name": { + "name": "company_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "group_id": { + "name": "group_id", + "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": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hubspot_deal_data": { + "name": "hubspot_deal_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "deal_id": { + "name": "deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dealname": { + "name": "dealname", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dealstage": { + "name": "dealstage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "company_id": { + "name": "company_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "project_code": { + "name": "project_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "landlord_property_id": { + "name": "landlord_property_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "listing_id": { + "name": "listing_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uprn": { + "name": "uprn", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "outcome": { + "name": "outcome", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "outcome_notes": { + "name": "outcome_notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "major_condition_issue_description": { + "name": "major_condition_issue_description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "major_condition_issue_photos": { + "name": "major_condition_issue_photos", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "major_condition_issue_evidence_s3_url": { + "name": "major_condition_issue_evidence_s3_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "coordination_status": { + "name": "coordination_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "design_status": { + "name": "design_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "booking_status": { + "name": "booking_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pashub_link": { + "name": "pashub_link", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sharepoint_link": { + "name": "sharepoint_link", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dampmould_growth": { + "name": "dampmould_growth", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pre_sap": { + "name": "pre_sap", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "coordinator": { + "name": "coordinator", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mtp_completion_date": { + "name": "mtp_completion_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "mtp_re_model_completion_date": { + "name": "mtp_re_model_completion_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "ioe_v3_completion_date": { + "name": "ioe_v3_completion_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "proposed_measures": { + "name": "proposed_measures", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "approved_package": { + "name": "approved_package", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "designer": { + "name": "designer", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "design_type": { + "name": "design_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "design_completion_date": { + "name": "design_completion_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "actual_measures_installed": { + "name": "actual_measures_installed", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "installer": { + "name": "installer", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "installer_handover": { + "name": "installer_handover", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lodgement_status": { + "name": "lodgement_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "measures_lodgement_date": { + "name": "measures_lodgement_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "lodgement_date": { + "name": "lodgement_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "expected_commencement_date": { + "name": "expected_commencement_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "coordination_comments": { + "name": "coordination_comments", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "surveyor": { + "name": "surveyor", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "damp_mould_and_repairs_comments": { + "name": "damp_mould_and_repairs_comments", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "batch": { + "name": "batch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "batch_description": { + "name": "batch_description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "block_reference": { + "name": "block_reference", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "nonfunded_measures": { + "name": "nonfunded_measures", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_prn": { + "name": "epc_prn", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "potential_post_sap_score_dropdown": { + "name": "potential_post_sap_score_dropdown", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ei_score": { + "name": "ei_score", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ei_score__potential_": { + "name": "ei_score__potential_", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_sap_score": { + "name": "epc_sap_score", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_sap_score__potential_": { + "name": "epc_sap_score__potential_", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmed_survey_date": { + "name": "confirmed_survey_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "confirmed_survey_time": { + "name": "confirmed_survey_time", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "surveyed_date": { + "name": "surveyed_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "survey_type": { + "name": "survey_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "measures_for_pibi_ordered": { + "name": "measures_for_pibi_ordered", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pibi_order_date": { + "name": "pibi_order_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "pibi_completed_date": { + "name": "pibi_completed_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "property_halted_date": { + "name": "property_halted_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "property_halted_reason": { + "name": "property_halted_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "technical_approved_measures_for_install": { + "name": "technical_approved_measures_for_install", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sent_to_installer_for_pricing": { + "name": "sent_to_installer_for_pricing", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "domna_survey_required": { + "name": "domna_survey_required", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "domna_survey_type": { + "name": "domna_survey_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "domna_survey_date": { + "name": "domna_survey_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "date_booking_made": { + "name": "date_booking_made", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "last_contact_date": { + "name": "last_contact_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "last_outbound_call": { + "name": "last_outbound_call", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "last_outbound_email": { + "name": "last_outbound_email", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "last_submission_date": { + "name": "last_submission_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "number_of_attempts": { + "name": "number_of_attempts", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "client_booking_reference": { + "name": "client_booking_reference", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "third_party_surveyor_identifier": { + "name": "third_party_surveyor_identifier", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "design_constraints": { + "name": "design_constraints", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "planning_comments": { + "name": "planning_comments", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "planning_status": { + "name": "planning_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "planning_suggested_approach": { + "name": "planning_suggested_approach", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "planning_authority": { + "name": "planning_authority", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "designated_area": { + "name": "designated_area", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "article_4_pd_rights": { + "name": "article_4_pd_rights", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "listed_building": { + "name": "listed_building", + "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": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hubspot_projects_data": { + "name": "hubspot_projects_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "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": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "hubspot_projects_data_project_id_unique": { + "name": "hubspot_projects_data_project_id_unique", + "nullsNotDistinct": false, + "columns": [ + "project_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.hubspot_users": { + "name": "hubspot_users", + "schema": "", + "columns": { + "hubspot_owner_id": { + "name": "hubspot_owner_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "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.epc_store": { + "name": "epc_store", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "epc_api_created_at": { + "name": "epc_api_created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "epc_api": { + "name": "epc_api", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "epc_page_created_at": { + "name": "epc_page_created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "epc_page": { + "name": "epc_page", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "epc_page_rrn": { + "name": "epc_page_rrn", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "uq_epc_store_uprn": { + "name": "uq_epc_store_uprn", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.files_from_surveyor": { + "name": "files_from_surveyor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "s3_json_url": { + "name": "s3_json_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "files_from_surveyor_portfolio_id_portfolio_id_fk": { + "name": "files_from_surveyor_portfolio_id_portfolio_id_fk", + "tableFrom": "files_from_surveyor", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "files_from_surveyor_property_id_property_id_fk": { + "name": "files_from_surveyor_property_id_property_id_fk", + "tableFrom": "files_from_surveyor", + "tableTo": "property", + "columnsFrom": [ + "property_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.inspections": { + "name": "inspections", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "archetype": { + "name": "archetype", + "type": "inspection_archetype", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "archetype_2": { + "name": "archetype_2", + "type": "inspection_archetype_2", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "wall_construction": { + "name": "wall_construction", + "type": "inspections_wall_construction", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "insulation": { + "name": "insulation", + "type": "inspections_wall_insulation", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "insulation_material": { + "name": "insulation_material", + "type": "inspections_insulation_material", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "borescoped": { + "name": "borescoped", + "type": "inspection_borescoped", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "roof_orientation": { + "name": "roof_orientation", + "type": "inspections_roof_orientation", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "tile_hung": { + "name": "tile_hung", + "type": "inspections_tile_hung", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "rendered": { + "name": "rendered", + "type": "inspections_rendered", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "cladding": { + "name": "cladding", + "type": "inspections_cladding", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "access_issues": { + "name": "access_issues", + "type": "inspections_access_issues", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "surveyor_name": { + "name": "surveyor_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "inspections_property_id_property_id_fk": { + "name": "inspections_property_id_property_id_fk", + "tableFrom": "inspections", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_built_form_type_overrides": { + "name": "landlord_built_form_type_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "built_form_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_built_form_type_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_built_form_type_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_built_form_type_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_built_form_type_overrides_portfolio_description_unique": { + "name": "landlord_built_form_type_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_construction_age_band_overrides": { + "name": "landlord_construction_age_band_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "construction_age_band", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_construction_age_band_overrides_portfolio_fk": { + "name": "landlord_construction_age_band_overrides_portfolio_fk", + "tableFrom": "landlord_construction_age_band_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_construction_age_band_portfolio_description_unique": { + "name": "landlord_construction_age_band_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_glazing_overrides": { + "name": "landlord_glazing_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "glazing", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_glazing_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_glazing_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_glazing_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_glazing_overrides_portfolio_description_unique": { + "name": "landlord_glazing_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_main_fuel_overrides": { + "name": "landlord_main_fuel_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "main_fuel", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_main_fuel_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_main_fuel_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_main_fuel_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_main_fuel_overrides_portfolio_description_unique": { + "name": "landlord_main_fuel_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_main_heating_system_overrides": { + "name": "landlord_main_heating_system_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "main_heating_system", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_main_heating_system_overrides_portfolio_fk": { + "name": "landlord_main_heating_system_overrides_portfolio_fk", + "tableFrom": "landlord_main_heating_system_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_main_heating_system_portfolio_description_unique": { + "name": "landlord_main_heating_system_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_property_type_overrides": { + "name": "landlord_property_type_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "property_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_property_type_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_property_type_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_property_type_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_property_type_overrides_portfolio_description_unique": { + "name": "landlord_property_type_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_roof_type_overrides": { + "name": "landlord_roof_type_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "roof_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_roof_type_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_roof_type_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_roof_type_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_roof_type_overrides_portfolio_description_unique": { + "name": "landlord_roof_type_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_wall_type_overrides": { + "name": "landlord_wall_type_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "wall_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_wall_type_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_wall_type_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_wall_type_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_wall_type_overrides_portfolio_description_unique": { + "name": "landlord_wall_type_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.landlord_water_heating_overrides": { + "name": "landlord_water_heating_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "water_heating", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "override_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "landlord_water_heating_overrides_portfolio_id_portfolio_id_fk": { + "name": "landlord_water_heating_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "landlord_water_heating_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "landlord_water_heating_overrides_portfolio_description_unique": { + "name": "landlord_water_heating_overrides_portfolio_description_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "description" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_door_ventilation": { + "name": "magic_plan_door_ventilation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_door_id": { + "name": "magic_plan_door_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "undercut_mm": { + "name": "undercut_mm", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_door_ventilation_magic_plan_door_id_magic_plan_door_id_fk": { + "name": "magic_plan_door_ventilation_magic_plan_door_id_magic_plan_door_id_fk", + "tableFrom": "magic_plan_door_ventilation", + "tableTo": "magic_plan_door", + "columnsFrom": [ + "magic_plan_door_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "magic_plan_door_ventilation_magic_plan_door_id_unique": { + "name": "magic_plan_door_ventilation_magic_plan_door_id_unique", + "nullsNotDistinct": false, + "columns": [ + "magic_plan_door_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_door": { + "name": "magic_plan_door", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_room_id": { + "name": "magic_plan_room_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "width_mm": { + "name": "width_mm", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "height_mm": { + "name": "height_mm", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_door_magic_plan_room_id_magic_plan_room_id_fk": { + "name": "magic_plan_door_magic_plan_room_id_magic_plan_room_id_fk", + "tableFrom": "magic_plan_door", + "tableTo": "magic_plan_room", + "columnsFrom": [ + "magic_plan_room_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_floor": { + "name": "magic_plan_floor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_plan_id": { + "name": "magic_plan_plan_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "level": { + "name": "level", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_floor_magic_plan_plan_id_magic_plan_plan_id_fk": { + "name": "magic_plan_floor_magic_plan_plan_id_magic_plan_plan_id_fk", + "tableFrom": "magic_plan_floor", + "tableTo": "magic_plan_plan", + "columnsFrom": [ + "magic_plan_plan_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_plan": { + "name": "magic_plan_plan", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address": { + "name": "address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "magic_plan_uid": { + "name": "magic_plan_uid", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uploaded_file_id": { + "name": "uploaded_file_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_plan_uploaded_file_id_uploaded_files_id_fk": { + "name": "magic_plan_plan_uploaded_file_id_uploaded_files_id_fk", + "tableFrom": "magic_plan_plan", + "tableTo": "uploaded_files", + "columnsFrom": [ + "uploaded_file_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "magic_plan_plan_magic_plan_uid_unique": { + "name": "magic_plan_plan_magic_plan_uid_unique", + "nullsNotDistinct": false, + "columns": [ + "magic_plan_uid" + ] + }, + "magic_plan_plan_uploaded_file_id_unique": { + "name": "magic_plan_plan_uploaded_file_id_unique", + "nullsNotDistinct": false, + "columns": [ + "uploaded_file_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_room": { + "name": "magic_plan_room", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_floor_id": { + "name": "magic_plan_floor_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "width_m": { + "name": "width_m", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "length_m": { + "name": "length_m", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "area_m2": { + "name": "area_m2", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_room_magic_plan_floor_id_magic_plan_floor_id_fk": { + "name": "magic_plan_room_magic_plan_floor_id_magic_plan_floor_id_fk", + "tableFrom": "magic_plan_room", + "tableTo": "magic_plan_floor", + "columnsFrom": [ + "magic_plan_floor_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_window_ventilation": { + "name": "magic_plan_window_ventilation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_window_id": { + "name": "magic_plan_window_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "opening_type": { + "name": "opening_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "num_openings": { + "name": "num_openings", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "pct_openable": { + "name": "pct_openable", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "trickle_vent_area_mm2": { + "name": "trickle_vent_area_mm2", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "num_trickle_vents": { + "name": "num_trickle_vents", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_window_ventilation_magic_plan_window_id_magic_plan_window_id_fk": { + "name": "magic_plan_window_ventilation_magic_plan_window_id_magic_plan_window_id_fk", + "tableFrom": "magic_plan_window_ventilation", + "tableTo": "magic_plan_window", + "columnsFrom": [ + "magic_plan_window_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "magic_plan_window_ventilation_magic_plan_window_id_unique": { + "name": "magic_plan_window_ventilation_magic_plan_window_id_unique", + "nullsNotDistinct": false, + "columns": [ + "magic_plan_window_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.magic_plan_window": { + "name": "magic_plan_window", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "magic_plan_room_id": { + "name": "magic_plan_room_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "width_m": { + "name": "width_m", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "height_m": { + "name": "height_m", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "area_m2": { + "name": "area_m2", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "magic_plan_window_magic_plan_room_id_magic_plan_room_id_fk": { + "name": "magic_plan_window_magic_plan_room_id_magic_plan_room_id_fk", + "tableFrom": "magic_plan_window", + "tableTo": "magic_plan_room", + "columnsFrom": [ + "magic_plan_room_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": { + "idx_material_active": { + "name": "idx_material_active", + "columns": [ + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"material\".\"is_active\"", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organisation": { + "name": "organisation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "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()" + }, + "hubspot_company_id": { + "name": "hubspot_company_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pibi_requests": { + "name": "pibi_requests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "ordered_at": { + "name": "ordered_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "pushed_at": { + "name": "pushed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_pibi_requests_deal_id": { + "name": "idx_pibi_requests_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_pibi_requests_portfolio_id": { + "name": "idx_pibi_requests_portfolio_id", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pibi_requests_portfolio_id_portfolio_id_fk": { + "name": "pibi_requests_portfolio_id_portfolio_id_fk", + "tableFrom": "pibi_requests", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "pibi_requests_created_by_user_id_user_id_fk": { + "name": "pibi_requests_created_by_user_id_user_id_fk", + "tableFrom": "pibi_requests", + "tableTo": "user", + "columnsFrom": [ + "created_by_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.portfolio_organisation": { + "name": "portfolio_organisation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "organisation_id": { + "name": "organisation_id", + "type": "uuid", + "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": { + "portfolio_organisation_portfolio_id_portfolio_id_fk": { + "name": "portfolio_organisation_portfolio_id_portfolio_id_fk", + "tableFrom": "portfolio_organisation", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "portfolio_organisation_organisation_id_organisation_id_fk": { + "name": "portfolio_organisation_organisation_id_organisation_id_fk", + "tableFrom": "portfolio_organisation", + "tableTo": "organisation", + "columnsFrom": [ + "organisation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "portfolio_organisation_portfolio_id_organisation_id_unique": { + "name": "portfolio_organisation_portfolio_id_organisation_id_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "organisation_id" + ] + } + }, + "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.portfolio_capabilities": { + "name": "portfolio_capabilities", + "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 + }, + "capability": { + "name": "capability", + "type": "portfolio_capability", + "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": { + "portfolio_capabilities_user_id_user_id_fk": { + "name": "portfolio_capabilities_user_id_user_id_fk", + "tableFrom": "portfolio_capabilities", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "portfolio_capabilities_portfolio_id_portfolio_id_fk": { + "name": "portfolio_capabilities_portfolio_id_portfolio_id_fk", + "tableFrom": "portfolio_capabilities", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "portfolio_capabilities_user_id_portfolio_id_capability_unique": { + "name": "portfolio_capabilities_user_id_portfolio_id_capability_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "portfolio_id", + "capability" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.portfolioInvitations": { + "name": "portfolioInvitations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "invited_by_user_id": { + "name": "invited_by_user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "portfolioInvitations_portfolio_id_portfolio_id_fk": { + "name": "portfolioInvitations_portfolio_id_portfolio_id_fk", + "tableFrom": "portfolioInvitations", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "portfolioInvitations_invited_by_user_id_user_id_fk": { + "name": "portfolioInvitations_invited_by_user_id_user_id_fk", + "tableFrom": "portfolioInvitations", + "tableTo": "user", + "columnsFrom": [ + "invited_by_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "portfolio_invitations_portfolio_email_unique": { + "name": "portfolio_invitations_portfolio_email_unique", + "nullsNotDistinct": false, + "columns": [ + "portfolio_id", + "email" + ] + } + }, + "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.project": { + "name": "project", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "organisation_id": { + "name": "organisation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "project_type_id": { + "name": "project_type_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start_date": { + "name": "start_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "end_date": { + "name": "end_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "domna_admin_access": { + "name": "domna_admin_access", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "sharepoint_base_url": { + "name": "sharepoint_base_url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "sharepoint_sub_folder_template": { + "name": "sharepoint_sub_folder_template", + "type": "varchar", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "project_organisation_id_organisation_id_fk": { + "name": "project_organisation_id_organisation_id_fk", + "tableFrom": "project", + "tableTo": "organisation", + "columnsFrom": [ + "organisation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_project_type_id_project_type_id_fk": { + "name": "project_project_type_id_project_type_id_fk", + "tableFrom": "project", + "tableTo": "project_type", + "columnsFrom": [ + "project_type_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_property": { + "name": "project_property", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "project_property_project_id_project_id_fk": { + "name": "project_property_project_id_project_id_fk", + "tableFrom": "project_property", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_property_property_id_property_id_fk": { + "name": "project_property_property_id_property_id_fk", + "tableFrom": "project_property", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "project_property_project_id_property_id_unique": { + "name": "project_property_project_id_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "project_id", + "property_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_type": { + "name": "project_type", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_workstream": { + "name": "project_workstream", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "workstream_id": { + "name": "workstream_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "current_stage_id": { + "name": "current_stage_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "project_workstream_project_id_project_id_fk": { + "name": "project_workstream_project_id_project_id_fk", + "tableFrom": "project_workstream", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_workstream_workstream_id_workstream_id_fk": { + "name": "project_workstream_workstream_id_workstream_id_fk", + "tableFrom": "project_workstream", + "tableTo": "workstream", + "columnsFrom": [ + "workstream_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_workstream_current_stage_id_project_workstream_stage_id_fk": { + "name": "project_workstream_current_stage_id_project_workstream_stage_id_fk", + "tableFrom": "project_workstream", + "tableTo": "project_workstream_stage", + "columnsFrom": [ + "current_stage_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_workstream_contractor": { + "name": "project_workstream_contractor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_workstream_id": { + "name": "project_workstream_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "organisation_id": { + "name": "organisation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "update_stages_permission": { + "name": "update_stages_permission", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "upload_documents_permission": { + "name": "upload_documents_permission", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "assigned_at": { + "name": "assigned_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "project_workstream_contractor_project_workstream_id_project_workstream_id_fk": { + "name": "project_workstream_contractor_project_workstream_id_project_workstream_id_fk", + "tableFrom": "project_workstream_contractor", + "tableTo": "project_workstream", + "columnsFrom": [ + "project_workstream_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_workstream_contractor_organisation_id_organisation_id_fk": { + "name": "project_workstream_contractor_organisation_id_organisation_id_fk", + "tableFrom": "project_workstream_contractor", + "tableTo": "organisation", + "columnsFrom": [ + "organisation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_workstream_evidence_requirement": { + "name": "project_workstream_evidence_requirement", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_workstream_id": { + "name": "project_workstream_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "file_type": { + "name": "file_type", + "type": "file_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "project_workstream_stage_id": { + "name": "project_workstream_stage_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "required": { + "name": "required", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "naming_rule": { + "name": "naming_rule", + "type": "varchar", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "project_workstream_evidence_requirement_project_workstream_id_project_workstream_id_fk": { + "name": "project_workstream_evidence_requirement_project_workstream_id_project_workstream_id_fk", + "tableFrom": "project_workstream_evidence_requirement", + "tableTo": "project_workstream", + "columnsFrom": [ + "project_workstream_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_workstream_evidence_requirement_project_workstream_stage_id_project_workstream_stage_id_fk": { + "name": "project_workstream_evidence_requirement_project_workstream_stage_id_project_workstream_stage_id_fk", + "tableFrom": "project_workstream_evidence_requirement", + "tableTo": "project_workstream_stage", + "columnsFrom": [ + "project_workstream_stage_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_workstream_stage": { + "name": "project_workstream_stage", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "project_workstream_id": { + "name": "project_workstream_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "start_date": { + "name": "start_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "due_date": { + "name": "due_date", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "last_updated": { + "name": "last_updated", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status_description": { + "name": "status_description", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "project_workstream_stage_project_workstream_id_project_workstream_id_fk": { + "name": "project_workstream_stage_project_workstream_id_project_workstream_id_fk", + "tableFrom": "project_workstream_stage", + "tableTo": "project_workstream", + "columnsFrom": [ + "project_workstream_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.work_order": { + "name": "work_order", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "reference": { + "name": "reference", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "project_workstream_contractor_id": { + "name": "project_workstream_contractor_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "project_workstream_stage_id": { + "name": "project_workstream_stage_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "forecast_end": { + "name": "forecast_end", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "priority": { + "name": "priority", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "work_order_project_workstream_contractor_id_project_workstream_contractor_id_fk": { + "name": "work_order_project_workstream_contractor_id_project_workstream_contractor_id_fk", + "tableFrom": "work_order", + "tableTo": "project_workstream_contractor", + "columnsFrom": [ + "project_workstream_contractor_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "work_order_property_id_property_id_fk": { + "name": "work_order_property_id_property_id_fk", + "tableFrom": "work_order", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "work_order_project_workstream_stage_id_project_workstream_stage_id_fk": { + "name": "work_order_project_workstream_stage_id_project_workstream_stage_id_fk", + "tableFrom": "work_order", + "tableTo": "project_workstream_stage", + "columnsFrom": [ + "project_workstream_stage_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "work_order_reference_unique": { + "name": "work_order_reference_unique", + "nullsNotDistinct": false, + "columns": [ + "reference" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workstream": { + "name": "workstream", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_overrides": { + "name": "property_overrides", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "building_part": { + "name": "building_part", + "type": "smallint", + "primaryKey": false, + "notNull": true + }, + "override_component": { + "name": "override_component", + "type": "override_component", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "override_value": { + "name": "override_value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "original_spreadsheet_description": { + "name": "original_spreadsheet_description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "property_overrides_property_id_property_id_fk": { + "name": "property_overrides_property_id_property_id_fk", + "tableFrom": "property_overrides", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "property_overrides_portfolio_id_portfolio_id_fk": { + "name": "property_overrides_portfolio_id_portfolio_id_fk", + "tableFrom": "property_overrides", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "property_overrides_property_component_part_unique": { + "name": "property_overrides_property_component_part_unique", + "nullsNotDistinct": false, + "columns": [ + "property_id", + "override_component", + "building_part" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_building_part": { + "name": "epc_building_part", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "construction_age_band": { + "name": "construction_age_band", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "wall_construction": { + "name": "wall_construction", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "wall_insulation_type": { + "name": "wall_insulation_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "wall_thickness_measured": { + "name": "wall_thickness_measured", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "party_wall_construction": { + "name": "party_wall_construction", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "building_part_number": { + "name": "building_part_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "wall_dry_lined": { + "name": "wall_dry_lined", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "wall_thickness_mm": { + "name": "wall_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "wall_insulation_thickness": { + "name": "wall_insulation_thickness", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "wall_insulation_thermal_conductivity": { + "name": "wall_insulation_thermal_conductivity", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "floor_heat_loss": { + "name": "floor_heat_loss", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "floor_insulation_thickness": { + "name": "floor_insulation_thickness", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "flat_roof_insulation_thickness": { + "name": "flat_roof_insulation_thickness", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "floor_type": { + "name": "floor_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "floor_construction_type": { + "name": "floor_construction_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "floor_insulation_type_str": { + "name": "floor_insulation_type_str", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "floor_u_value_known": { + "name": "floor_u_value_known", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "roof_construction": { + "name": "roof_construction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "roof_insulation_location": { + "name": "roof_insulation_location", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "roof_insulation_thickness": { + "name": "roof_insulation_thickness", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "rafter_insulation_thickness": { + "name": "rafter_insulation_thickness", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "roof_construction_type": { + "name": "roof_construction_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "curtain_wall_age": { + "name": "curtain_wall_age", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "wall_is_basement": { + "name": "wall_is_basement", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "wall_u_value": { + "name": "wall_u_value", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_area": { + "name": "alt_wall_1_area", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_dry_lined": { + "name": "alt_wall_1_dry_lined", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_construction": { + "name": "alt_wall_1_construction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_insulation_type": { + "name": "alt_wall_1_insulation_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_thickness_measured": { + "name": "alt_wall_1_thickness_measured", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_insulation_thickness": { + "name": "alt_wall_1_insulation_thickness", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_is_sheltered": { + "name": "alt_wall_1_is_sheltered", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_u_value": { + "name": "alt_wall_1_u_value", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_thickness_mm": { + "name": "alt_wall_1_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_1_is_basement": { + "name": "alt_wall_1_is_basement", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_area": { + "name": "alt_wall_2_area", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_dry_lined": { + "name": "alt_wall_2_dry_lined", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_construction": { + "name": "alt_wall_2_construction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_insulation_type": { + "name": "alt_wall_2_insulation_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_thickness_measured": { + "name": "alt_wall_2_thickness_measured", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_insulation_thickness": { + "name": "alt_wall_2_insulation_thickness", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_is_sheltered": { + "name": "alt_wall_2_is_sheltered", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_u_value": { + "name": "alt_wall_2_u_value", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_thickness_mm": { + "name": "alt_wall_2_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "alt_wall_2_is_basement": { + "name": "alt_wall_2_is_basement", + "type": "boolean", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "ix_epc_building_part_epc_property": { + "name": "ix_epc_building_part_epc_property", + "columns": [ + { + "expression": "epc_property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_building_part_epc_property_id_epc_property_id_fk": { + "name": "epc_building_part_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_building_part", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_energy_element": { + "name": "epc_energy_element", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "element_type": { + "name": "element_type", + "type": "energy_element_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "energy_efficiency_rating": { + "name": "energy_efficiency_rating", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "environmental_efficiency_rating": { + "name": "environmental_efficiency_rating", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "ix_epc_energy_element_epc_property": { + "name": "ix_epc_energy_element_epc_property", + "columns": [ + { + "expression": "epc_property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_energy_element_epc_property_id_epc_property_id_fk": { + "name": "epc_energy_element_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_energy_element", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_flat_details": { + "name": "epc_flat_details", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "level": { + "name": "level", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "top_storey": { + "name": "top_storey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "flat_location": { + "name": "flat_location", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "heat_loss_corridor": { + "name": "heat_loss_corridor", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "storey_count": { + "name": "storey_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "unheated_corridor_length_m": { + "name": "unheated_corridor_length_m", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_flat_details_epc_property_id_epc_property_id_fk": { + "name": "epc_flat_details_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_flat_details", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_flat_details_epc_property_id_unique": { + "name": "epc_flat_details_epc_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "epc_property_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_floor_dimension": { + "name": "epc_floor_dimension", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_building_part_id": { + "name": "epc_building_part_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "floor": { + "name": "floor", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "room_height_m": { + "name": "room_height_m", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "total_floor_area_m2": { + "name": "total_floor_area_m2", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "party_wall_length_m": { + "name": "party_wall_length_m", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "heat_loss_perimeter_m": { + "name": "heat_loss_perimeter_m", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "floor_insulation": { + "name": "floor_insulation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "floor_construction": { + "name": "floor_construction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "is_exposed_floor": { + "name": "is_exposed_floor", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_above_partially_heated_space": { + "name": "is_above_partially_heated_space", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "ix_epc_floor_dimension_building_part": { + "name": "ix_epc_floor_dimension_building_part", + "columns": [ + { + "expression": "epc_building_part_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_floor_dimension_epc_building_part_id_epc_building_part_id_fk": { + "name": "epc_floor_dimension_epc_building_part_id_epc_building_part_id_fk", + "tableFrom": "epc_floor_dimension", + "tableTo": "epc_building_part", + "columnsFrom": [ + "epc_building_part_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_main_heating_detail": { + "name": "epc_main_heating_detail", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "has_fghrs": { + "name": "has_fghrs", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "main_fuel_type": { + "name": "main_fuel_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "heat_emitter_type": { + "name": "heat_emitter_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "emitter_temperature": { + "name": "emitter_temperature", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "main_heating_control": { + "name": "main_heating_control", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "fan_flue_present": { + "name": "fan_flue_present", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "boiler_flue_type": { + "name": "boiler_flue_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "boiler_ignition_type": { + "name": "boiler_ignition_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "central_heating_pump_age": { + "name": "central_heating_pump_age", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "central_heating_pump_age_str": { + "name": "central_heating_pump_age_str", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "main_heating_index_number": { + "name": "main_heating_index_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "sap_main_heating_code": { + "name": "sap_main_heating_code", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "main_heating_number": { + "name": "main_heating_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "main_heating_category": { + "name": "main_heating_category", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "main_heating_fraction": { + "name": "main_heating_fraction", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "main_heating_data_source": { + "name": "main_heating_data_source", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "condensing": { + "name": "condensing", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "weather_compensator": { + "name": "weather_compensator", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "community_heating_boiler_fuel_type": { + "name": "community_heating_boiler_fuel_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "community_heating_chp_fraction": { + "name": "community_heating_chp_fraction", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "ix_epc_main_heating_detail_epc_property": { + "name": "ix_epc_main_heating_detail_epc_property", + "columns": [ + { + "expression": "epc_property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_main_heating_detail_epc_property_id_epc_property_id_fk": { + "name": "epc_main_heating_detail_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_main_heating_detail", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_photovoltaic_array": { + "name": "epc_photovoltaic_array", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "array_index": { + "name": "array_index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "peak_power": { + "name": "peak_power", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "pitch": { + "name": "pitch", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "overshading": { + "name": "overshading", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "orientation": { + "name": "orientation", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_photovoltaic_array_epc_property_id_epc_property_id_fk": { + "name": "epc_photovoltaic_array_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_photovoltaic_array", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_property": { + "name": "epc_property", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "uploaded_file_id": { + "name": "uploaded_file_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'lodged'" + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "uprn_source": { + "name": "uprn_source", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "report_reference": { + "name": "report_reference", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "report_type": { + "name": "report_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "assessment_type": { + "name": "assessment_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sap_version": { + "name": "sap_version", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "schema_type": { + "name": "schema_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "schema_versions_original": { + "name": "schema_versions_original", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "calculation_software_version": { + "name": "calculation_software_version", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address_line_1": { + "name": "address_line_1", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "address_line_2": { + "name": "address_line_2", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "post_town": { + "name": "post_town", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "region_code": { + "name": "region_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "country_code": { + "name": "country_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "language_code": { + "name": "language_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dwelling_type": { + "name": "dwelling_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "property_type": { + "name": "property_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "built_form": { + "name": "built_form", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tenure": { + "name": "tenure", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "transaction_type": { + "name": "transaction_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "inspection_date": { + "name": "inspection_date", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "completion_date": { + "name": "completion_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "registration_date": { + "name": "registration_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "total_floor_area_m2": { + "name": "total_floor_area_m2", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "measurement_type": { + "name": "measurement_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "solar_water_heating": { + "name": "solar_water_heating", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "has_hot_water_cylinder": { + "name": "has_hot_water_cylinder", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "has_fixed_air_conditioning": { + "name": "has_fixed_air_conditioning", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "has_conservatory": { + "name": "has_conservatory", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "has_heated_separate_conservatory": { + "name": "has_heated_separate_conservatory", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "conservatory_type": { + "name": "conservatory_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "conservatory_floor_area_m2": { + "name": "conservatory_floor_area_m2", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "conservatory_glazed_perimeter_m": { + "name": "conservatory_glazed_perimeter_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "conservatory_double_glazed": { + "name": "conservatory_double_glazed", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "conservatory_thermally_separated": { + "name": "conservatory_thermally_separated", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "conservatory_room_height_storeys": { + "name": "conservatory_room_height_storeys", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "door_count": { + "name": "door_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "wet_rooms_count": { + "name": "wet_rooms_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "extensions_count": { + "name": "extensions_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "heated_rooms_count": { + "name": "heated_rooms_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "open_chimneys_count": { + "name": "open_chimneys_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "habitable_rooms_count": { + "name": "habitable_rooms_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "insulated_door_count": { + "name": "insulated_door_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "cfl_fixed_lighting_bulbs_count": { + "name": "cfl_fixed_lighting_bulbs_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "led_fixed_lighting_bulbs_count": { + "name": "led_fixed_lighting_bulbs_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "incandescent_fixed_lighting_bulbs_count": { + "name": "incandescent_fixed_lighting_bulbs_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "blocked_chimneys_count": { + "name": "blocked_chimneys_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "draughtproofed_door_count": { + "name": "draughtproofed_door_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "energy_rating_average": { + "name": "energy_rating_average", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "low_energy_fixed_lighting_bulbs_count": { + "name": "low_energy_fixed_lighting_bulbs_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "fixed_lighting_outlets_count": { + "name": "fixed_lighting_outlets_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "low_energy_fixed_lighting_outlets_count": { + "name": "low_energy_fixed_lighting_outlets_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "number_of_storeys": { + "name": "number_of_storeys", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "any_unheated_rooms": { + "name": "any_unheated_rooms", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "hydro": { + "name": "hydro", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "photovoltaic_array": { + "name": "photovoltaic_array", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "waste_water_heat_recovery": { + "name": "waste_water_heat_recovery", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pressure_test": { + "name": "pressure_test", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "pressure_test_certificate_number": { + "name": "pressure_test_certificate_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "percent_draughtproofed": { + "name": "percent_draughtproofed", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "insulated_door_u_value": { + "name": "insulated_door_u_value", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "multiple_glazed_proportion": { + "name": "multiple_glazed_proportion", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "windows_transmission_u_value": { + "name": "windows_transmission_u_value", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "windows_transmission_data_source": { + "name": "windows_transmission_data_source", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "windows_transmission_solar_transmittance": { + "name": "windows_transmission_solar_transmittance", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_gas_connection_available": { + "name": "energy_gas_connection_available", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "energy_meter_type": { + "name": "energy_meter_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "energy_pv_battery_count": { + "name": "energy_pv_battery_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "energy_wind_turbines_count": { + "name": "energy_wind_turbines_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "energy_gas_smart_meter_present": { + "name": "energy_gas_smart_meter_present", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "energy_is_dwelling_export_capable": { + "name": "energy_is_dwelling_export_capable", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "energy_wind_turbines_terrain_type": { + "name": "energy_wind_turbines_terrain_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "energy_electricity_smart_meter_present": { + "name": "energy_electricity_smart_meter_present", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "energy_pv_connection": { + "name": "energy_pv_connection", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "energy_pv_percent_roof_area": { + "name": "energy_pv_percent_roof_area", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "energy_pv_battery_capacity": { + "name": "energy_pv_battery_capacity", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_wind_turbine_hub_height": { + "name": "energy_wind_turbine_hub_height", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_wind_turbine_rotor_diameter": { + "name": "energy_wind_turbine_rotor_diameter", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_pv_diverter_present": { + "name": "energy_pv_diverter_present", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "heating_cylinder_size": { + "name": "heating_cylinder_size", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_water_heating_code": { + "name": "heating_water_heating_code", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_water_heating_fuel": { + "name": "heating_water_heating_fuel", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_immersion_heating_type": { + "name": "heating_immersion_heating_type", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_insulation_type": { + "name": "heating_cylinder_insulation_type", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_thermostat": { + "name": "heating_cylinder_thermostat", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "heating_secondary_fuel_type": { + "name": "heating_secondary_fuel_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_secondary_heating_type": { + "name": "heating_secondary_heating_type", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_insulation_thickness_mm": { + "name": "heating_cylinder_insulation_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_volume_measured_l": { + "name": "heating_cylinder_volume_measured_l", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_cylinder_heat_loss": { + "name": "heating_cylinder_heat_loss", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "heating_wwhrs_index_number_1": { + "name": "heating_wwhrs_index_number_1", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_wwhrs_index_number_2": { + "name": "heating_wwhrs_index_number_2", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_shower_outlet_type": { + "name": "heating_shower_outlet_type", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_shower_wwhrs": { + "name": "heating_shower_wwhrs", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_type": { + "name": "ventilation_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ventilation_draught_lobby": { + "name": "ventilation_draught_lobby", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "ventilation_pressure_test": { + "name": "ventilation_pressure_test", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ventilation_open_flues_count": { + "name": "ventilation_open_flues_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_closed_flues_count": { + "name": "ventilation_closed_flues_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_boiler_flues_count": { + "name": "ventilation_boiler_flues_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_other_flues_count": { + "name": "ventilation_other_flues_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_extract_fans_count": { + "name": "ventilation_extract_fans_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_passive_vents_count": { + "name": "ventilation_passive_vents_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_flueless_gas_fires_count": { + "name": "ventilation_flueless_gas_fires_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_in_pcdf_database": { + "name": "ventilation_in_pcdf_database", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "mechanical_ventilation": { + "name": "mechanical_ventilation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_duct_type": { + "name": "mechanical_vent_duct_type", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_duct_placement": { + "name": "mechanical_vent_duct_placement", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_duct_insulation": { + "name": "mechanical_vent_duct_insulation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_ventilation_index_number": { + "name": "mechanical_ventilation_index_number", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_measured_installation": { + "name": "mechanical_vent_measured_installation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mechanical_vent_duct_insulation_level": { + "name": "mechanical_vent_duct_insulation_level", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "addendum_stone_walls": { + "name": "addendum_stone_walls", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "addendum_system_build": { + "name": "addendum_system_build", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "addendum_numbers": { + "name": "addendum_numbers", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "heating_number_baths": { + "name": "heating_number_baths", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_number_baths_wwhrs": { + "name": "heating_number_baths_wwhrs", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_electric_shower_count": { + "name": "heating_electric_shower_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_mixer_shower_count": { + "name": "heating_mixer_shower_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_present": { + "name": "ventilation_present", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "ventilation_sheltered_sides": { + "name": "ventilation_sheltered_sides", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ventilation_has_suspended_timber_floor": { + "name": "ventilation_has_suspended_timber_floor", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "ventilation_suspended_timber_floor_sealed": { + "name": "ventilation_suspended_timber_floor_sealed", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "ventilation_has_draught_lobby": { + "name": "ventilation_has_draught_lobby", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "ventilation_air_permeability_ap4_m3_h_m2": { + "name": "ventilation_air_permeability_ap4_m3_h_m2", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "ventilation_air_permeability_ap50_m3_h_m2": { + "name": "ventilation_air_permeability_ap50_m3_h_m2", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "ventilation_mechanical_ventilation_kind": { + "name": "ventilation_mechanical_ventilation_kind", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "uq_epc_property_property_portfolio": { + "name": "uq_epc_property_property_portfolio", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "ix_epc_property_property_source": { + "name": "ix_epc_property_property_source", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_property_property_id_property_id_fk": { + "name": "epc_property_property_id_property_id_fk", + "tableFrom": "epc_property", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "epc_property_portfolio_id_portfolio_id_fk": { + "name": "epc_property_portfolio_id_portfolio_id_fk", + "tableFrom": "epc_property", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "epc_property_uploaded_file_id_uploaded_files_id_fk": { + "name": "epc_property_uploaded_file_id_uploaded_files_id_fk", + "tableFrom": "epc_property", + "tableTo": "uploaded_files", + "columnsFrom": [ + "uploaded_file_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_property_uploaded_file_id_unique": { + "name": "epc_property_uploaded_file_id_unique", + "nullsNotDistinct": false, + "columns": [ + "uploaded_file_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_property_energy_performance": { + "name": "epc_property_energy_performance", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "energy_rating_current": { + "name": "energy_rating_current", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "energy_consumption_current": { + "name": "energy_consumption_current", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "environmental_impact_current": { + "name": "environmental_impact_current", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_cost_current": { + "name": "heating_cost_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lighting_cost_current": { + "name": "lighting_cost_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "hot_water_cost_current": { + "name": "hot_water_cost_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_emissions_current": { + "name": "co2_emissions_current", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_emissions_current_per_floor_area": { + "name": "co2_emissions_current_per_floor_area", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "current_energy_efficiency_band": { + "name": "current_energy_efficiency_band", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "energy_rating_potential": { + "name": "energy_rating_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_consumption_potential": { + "name": "energy_consumption_potential", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "environmental_impact_potential": { + "name": "environmental_impact_potential", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "heating_cost_potential": { + "name": "heating_cost_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lighting_cost_potential": { + "name": "lighting_cost_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "hot_water_cost_potential": { + "name": "hot_water_cost_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_emissions_potential": { + "name": "co2_emissions_potential", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "potential_energy_efficiency_band": { + "name": "potential_energy_efficiency_band", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_property_energy_performance_epc_property_id_epc_property_id_fk": { + "name": "epc_property_energy_performance_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_property_energy_performance", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_property_energy_performance_epc_property_id_unique": { + "name": "epc_property_energy_performance_epc_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "epc_property_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_renewable_heat_incentive": { + "name": "epc_renewable_heat_incentive", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "space_heating_kwh": { + "name": "space_heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "water_heating_kwh": { + "name": "water_heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "impact_of_loft_insulation_kwh": { + "name": "impact_of_loft_insulation_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "impact_of_cavity_insulation_kwh": { + "name": "impact_of_cavity_insulation_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "impact_of_solid_wall_insulation_kwh": { + "name": "impact_of_solid_wall_insulation_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_renewable_heat_incentive_epc_property_id_epc_property_id_fk": { + "name": "epc_renewable_heat_incentive_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_renewable_heat_incentive", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_renewable_heat_incentive_epc_property_id_unique": { + "name": "epc_renewable_heat_incentive_epc_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "epc_property_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_roof_window": { + "name": "epc_roof_window", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "roof_window_index": { + "name": "roof_window_index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "area_m2": { + "name": "area_m2", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "u_value_raw": { + "name": "u_value_raw", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "orientation": { + "name": "orientation", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "pitch_deg": { + "name": "pitch_deg", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "g_perpendicular": { + "name": "g_perpendicular", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "frame_factor": { + "name": "frame_factor", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "glazing_type": { + "name": "glazing_type", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "window_location": { + "name": "window_location", + "type": "jsonb", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "uq_epc_roof_window_property_index": { + "name": "uq_epc_roof_window_property_index", + "columns": [ + { + "expression": "epc_property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "roof_window_index", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_roof_window_epc_property_id_epc_property_id_fk": { + "name": "epc_roof_window_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_roof_window", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_room_in_roof": { + "name": "epc_room_in_roof", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_building_part_id": { + "name": "epc_building_part_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "floor_area": { + "name": "floor_area", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "construction_age_band": { + "name": "construction_age_band", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "common_wall_length_m": { + "name": "common_wall_length_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "common_wall_height_m": { + "name": "common_wall_height_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "gable_1_length_m": { + "name": "gable_1_length_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "gable_1_height_m": { + "name": "gable_1_height_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "gable_2_length_m": { + "name": "gable_2_length_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "gable_2_height_m": { + "name": "gable_2_height_m", + "type": "double precision", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_room_in_roof_epc_building_part_id_epc_building_part_id_fk": { + "name": "epc_room_in_roof_epc_building_part_id_epc_building_part_id_fk", + "tableFrom": "epc_room_in_roof", + "tableTo": "epc_building_part", + "columnsFrom": [ + "epc_building_part_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "epc_room_in_roof_epc_building_part_id_unique": { + "name": "epc_room_in_roof_epc_building_part_id_unique", + "nullsNotDistinct": false, + "columns": [ + "epc_building_part_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_room_in_roof_surface": { + "name": "epc_room_in_roof_surface", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_room_in_roof_id": { + "name": "epc_room_in_roof_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "surface_index": { + "name": "surface_index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "area_m2": { + "name": "area_m2", + "type": "double precision", + "primaryKey": false, + "notNull": true + }, + "insulation_thickness_mm": { + "name": "insulation_thickness_mm", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "insulation_type": { + "name": "insulation_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "u_value": { + "name": "u_value", + "type": "double precision", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "uq_epc_room_in_roof_surface_index": { + "name": "uq_epc_room_in_roof_surface_index", + "columns": [ + { + "expression": "epc_room_in_roof_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "surface_index", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "epc_room_in_roof_surface_epc_room_in_roof_id_epc_room_in_roof_id_fk": { + "name": "epc_room_in_roof_surface_epc_room_in_roof_id_epc_room_in_roof_id_fk", + "tableFrom": "epc_room_in_roof_surface", + "tableTo": "epc_room_in_roof", + "columnsFrom": [ + "epc_room_in_roof_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.epc_window": { + "name": "epc_window", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "epc_property_id": { + "name": "epc_property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "glazing_gap": { + "name": "glazing_gap", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "orientation": { + "name": "orientation", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "window_type": { + "name": "window_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "glazing_type": { + "name": "glazing_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "window_width": { + "name": "window_width", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "window_height": { + "name": "window_height", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "draught_proofed": { + "name": "draught_proofed", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "window_location": { + "name": "window_location", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "window_wall_type": { + "name": "window_wall_type", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "permanent_shutters_present": { + "name": "permanent_shutters_present", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "frame_material": { + "name": "frame_material", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "frame_factor": { + "name": "frame_factor", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "permanent_shutters_insulated": { + "name": "permanent_shutters_insulated", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "transmission_u_value": { + "name": "transmission_u_value", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "transmission_data_source": { + "name": "transmission_data_source", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "transmission_solar_transmittance": { + "name": "transmission_solar_transmittance", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "epc_window_epc_property_id_epc_property_id_fk": { + "name": "epc_window_epc_property_id_epc_property_id_fk", + "tableFrom": "epc_window", + "tableTo": "epc_property", + "columnsFrom": [ + "epc_property_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 + }, + "certificate_number": { + "name": "certificate_number", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "landlord_property_id": { + "name": "landlord_property_id", + "type": "text", + "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 + }, + "user_inputted_address": { + "name": "user_inputted_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_inputted_postcode": { + "name": "user_inputted_postcode", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lexiscore": { + "name": "lexiscore", + "type": "real", + "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 + }, + "installed_measures_sap_point_adjustment": { + "name": "installed_measures_sap_point_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "is_sap_points_adjusted_for_installed_measures": { + "name": "is_sap_points_adjusted_for_installed_measures", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "original_sap_points": { + "name": "original_sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lodged_sap_points": { + "name": "lodged_sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lodged_epc_rating": { + "name": "lodged_epc_rating", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "marked_for_deletion": { + "name": "marked_for_deletion", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "uq_property_portfolio_uprn": { + "name": "uq_property_portfolio_uprn", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"property\".\"uprn\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "ix_property_portfolio": { + "name": "ix_property_portfolio", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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_baseline_performance": { + "name": "property_baseline_performance", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "lodged_sap_score": { + "name": "lodged_sap_score", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "lodged_epc_band": { + "name": "lodged_epc_band", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "lodged_co2_emissions_t_per_yr": { + "name": "lodged_co2_emissions_t_per_yr", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lodged_primary_energy_intensity_kwh_per_m2_yr": { + "name": "lodged_primary_energy_intensity_kwh_per_m2_yr", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "effective_sap_score": { + "name": "effective_sap_score", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "effective_epc_band": { + "name": "effective_epc_band", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "effective_co2_emissions_t_per_yr": { + "name": "effective_co2_emissions_t_per_yr", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "effective_primary_energy_intensity_kwh_per_m2_yr": { + "name": "effective_primary_energy_intensity_kwh_per_m2_yr", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "rebaseline_reason": { + "name": "rebaseline_reason", + "type": "rebaseline_reason", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "space_heating_kwh": { + "name": "space_heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "water_heating_kwh": { + "name": "water_heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "fuel_rates_period": { + "name": "fuel_rates_period", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "heating_kwh": { + "name": "heating_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "heating_cost_gbp": { + "name": "heating_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "hot_water_kwh": { + "name": "hot_water_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "hot_water_cost_gbp": { + "name": "hot_water_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lighting_kwh": { + "name": "lighting_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lighting_cost_gbp": { + "name": "lighting_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "appliances_kwh": { + "name": "appliances_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "appliances_cost_gbp": { + "name": "appliances_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cooking_kwh": { + "name": "cooking_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cooking_cost_gbp": { + "name": "cooking_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "pumps_fans_kwh": { + "name": "pumps_fans_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "pumps_fans_cost_gbp": { + "name": "pumps_fans_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cooling_kwh": { + "name": "cooling_kwh", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cooling_cost_gbp": { + "name": "cooling_cost_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "standing_charges_gbp": { + "name": "standing_charges_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "seg_credit_gbp": { + "name": "seg_credit_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "total_annual_bill_gbp": { + "name": "total_annual_bill_gbp", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "property_baseline_performance_property_id_property_id_fk": { + "name": "property_baseline_performance_property_id_property_id_fk", + "tableFrom": "property_baseline_performance", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "property_baseline_performance_property_id_unique": { + "name": "property_baseline_performance_property_id_unique", + "nullsNotDistinct": false, + "columns": [ + "property_id" + ] + } + }, + "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 + }, + "lodgement_date": { + "name": "lodgement_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "is_expired": { + "name": "is_expired", + "type": "boolean", + "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 + }, + "sap_05_overwritten": { + "name": "sap_05_overwritten", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "sap_05_score": { + "name": "sap_05_score", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "sap_05_epc_rating": { + "name": "sap_05_epc_rating", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": 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 + }, + "original_co2_emissions": { + "name": "original_co2_emissions", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "original_primary_energy_consumption": { + "name": "original_primary_energy_consumption", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "original_current_energy_demand": { + "name": "original_current_energy_demand", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "original_current_energy_demand_heating_hotwater": { + "name": "original_current_energy_demand_heating_hotwater", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "installed_measures_co2_adjustment": { + "name": "installed_measures_co2_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "installed_measures_energy_demand_adjustment": { + "name": "installed_measures_energy_demand_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "installed_measures_total_energy_bill_adjustment": { + "name": "installed_measures_total_energy_bill_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "installed_measures_heat_demand_adjustment": { + "name": "installed_measures_heat_demand_adjustment", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "is_epc_adjusted_for_installed_measures": { + "name": "is_epc_adjusted_for_installed_measures", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "lodged_co2_emissions": { + "name": "lodged_co2_emissions", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "lodged_heat_demand": { + "name": "lodged_heat_demand", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "has_been_remodelled": { + "name": "has_been_remodelled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "environment_impact_current": { + "name": "environment_impact_current", + "type": "real", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "uq_property_details_epc_property_portfolio": { + "name": "uq_property_details_epc_property_portfolio", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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": { + "uq_property_details_spatial_uprn": { + "name": "uq_property_details_spatial_uprn", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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.installed_measure": { + "name": "installed_measure", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "measure_type": { + "name": "measure_type", + "type": "measure_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "installed_at": { + "name": "installed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "sap_points": { + "name": "sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "carbon_savings": { + "name": "carbon_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "kwh_savings": { + "name": "kwh_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "bill_savings": { + "name": "bill_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "heat_demand_savings": { + "name": "heat_demand_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + } + }, + "indexes": { + "idx_installed_measure_uprn": { + "name": "idx_installed_measure_uprn", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_installed_measure_uprn_active": { + "name": "idx_installed_measure_uprn_active", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"installed_measure\".\"is_active\" = true", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_installed_measure_measure_type": { + "name": "idx_installed_measure_measure_type", + "columns": [ + { + "expression": "measure_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_installed_measure_uprn_measure": { + "name": "idx_installed_measure_uprn_measure", + "columns": [ + { + "expression": "uprn", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "measure_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"installed_measure\".\"is_active\" = true", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "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 + }, + "post_sap_points": { + "name": "post_sap_points", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "post_epc_rating": { + "name": "post_epc_rating", + "type": "epc", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "post_co2_emissions": { + "name": "post_co2_emissions", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "co2_savings": { + "name": "co2_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "post_energy_bill": { + "name": "post_energy_bill", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_bill_savings": { + "name": "energy_bill_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "post_energy_consumption": { + "name": "post_energy_consumption", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "energy_consumption_savings": { + "name": "energy_consumption_savings", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "valuation_post_retrofit": { + "name": "valuation_post_retrofit", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "valuation_increase": { + "name": "valuation_increase", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cost_of_works": { + "name": "cost_of_works", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "contingency_cost": { + "name": "contingency_cost", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "plan_type": { + "name": "plan_type", + "type": "plan_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_plan_portfolio_scenario": { + "name": "idx_plan_portfolio_scenario", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scenario_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_plan_latest_per_property": { + "name": "idx_plan_latest_per_property", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scenario_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_plan_property_default_latest": { + "name": "idx_plan_property_default_latest", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "where": "is_default = true", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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": { + "idx_plan_recommendations_plan_id": { + "name": "idx_plan_recommendations_plan_id", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_plan_recommendations_plan_rec": { + "name": "idx_plan_recommendations_plan_rec", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "recommendation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_plan_recommendations_recommendation_id": { + "name": "idx_plan_recommendations_recommendation_id", + "columns": [ + { + "expression": "recommendation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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 + }, + "plan_id": { + "name": "plan_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "material_id": { + "name": "material_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "material_quantity": { + "name": "material_quantity", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "material_quantity_unit": { + "name": "material_quantity_unit", + "type": "unit_quantity", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "material_depth": { + "name": "material_depth", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "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": { + "recommendation_property_id_idx": { + "name": "recommendation_property_id_idx", + "columns": [ + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_plan_id": { + "name": "idx_recommendation_plan_id", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_active_defaults": { + "name": "idx_recommendation_active_defaults", + "columns": [ + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"recommendation\".\"default\" = true AND \"recommendation\".\"already_installed\" = false", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_active_id_property": { + "name": "idx_recommendation_active_id_property", + "columns": [ + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"recommendation\".\"default\" = true AND \"recommendation\".\"already_installed\" = false", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_plan_default": { + "name": "idx_recommendation_plan_default", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "measure_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "property_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "estimated_cost", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"recommendation\".\"default\" = true AND \"recommendation\".\"already_installed\" = false", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_recommendation_material_id": { + "name": "idx_recommendation_material_id", + "columns": [ + { + "expression": "material_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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" + }, + "recommendation_plan_id_plan_id_fk": { + "name": "recommendation_plan_id_plan_id_fk", + "tableFrom": "recommendation", + "tableTo": "plan", + "columnsFrom": [ + "plan_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "recommendation_material_id_material_id_fk": { + "name": "recommendation_material_id_material_id_fk", + "tableFrom": "recommendation", + "tableTo": "material", + "columnsFrom": [ + "material_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "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": { + "recommendation_materials_recommendation_id_idx": { + "name": "recommendation_materials_recommendation_id_idx", + "columns": [ + { + "expression": "recommendation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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": "cascade", + "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 + }, + "fabric_first": { + "name": "fabric_first", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "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.property_removal_requests": { + "name": "property_removal_requests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'removal'" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "requested_by": { + "name": "requested_by", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "requested_at": { + "name": "requested_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "reviewed_by": { + "name": "reviewed_by", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "reviewed_at": { + "name": "reviewed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "original_batch": { + "name": "original_batch", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_removal_requests_deal_id": { + "name": "idx_removal_requests_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_removal_requests_portfolio_id": { + "name": "idx_removal_requests_portfolio_id", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "property_removal_requests_portfolio_id_portfolio_id_fk": { + "name": "property_removal_requests_portfolio_id_portfolio_id_fk", + "tableFrom": "property_removal_requests", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "property_removal_requests_requested_by_user_id_fk": { + "name": "property_removal_requests_requested_by_user_id_fk", + "tableFrom": "property_removal_requests", + "tableTo": "user", + "columnsFrom": [ + "requested_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "property_removal_requests_reviewed_by_user_id_fk": { + "name": "property_removal_requests_reviewed_by_user_id_fk", + "tableFrom": "property_removal_requests", + "tableTo": "user", + "columnsFrom": [ + "reviewed_by" + ], + "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.survey_requests": { + "name": "survey_requests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "survey_type": { + "name": "survey_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "requested_by": { + "name": "requested_by", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "requested_at": { + "name": "requested_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "fulfilled_at": { + "name": "fulfilled_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_survey_requests_deal_id": { + "name": "idx_survey_requests_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_survey_requests_portfolio_id": { + "name": "idx_survey_requests_portfolio_id", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "survey_requests_portfolio_id_portfolio_id_fk": { + "name": "survey_requests_portfolio_id_portfolio_id_fk", + "tableFrom": "survey_requests", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "survey_requests_requested_by_user_id_fk": { + "name": "survey_requests_requested_by_user_id_fk", + "tableFrom": "survey_requests", + "tableTo": "user", + "columnsFrom": [ + "requested_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.portfolio_tag": { + "name": "portfolio_tag", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "portfolio_id": { + "name": "portfolio_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "colour": { + "name": "colour", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "uq_portfolio_tag_portfolio_lower_name": { + "name": "uq_portfolio_tag_portfolio_lower_name", + "columns": [ + { + "expression": "portfolio_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"name\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "portfolio_tag_portfolio_id_portfolio_id_fk": { + "name": "portfolio_tag_portfolio_id_portfolio_id_fk", + "tableFrom": "portfolio_tag", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.property_tag": { + "name": "property_tag", + "schema": "", + "columns": { + "property_id": { + "name": "property_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "tag_id": { + "name": "tag_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "ix_property_tag_tag": { + "name": "ix_property_tag_tag", + "columns": [ + { + "expression": "tag_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "property_tag_property_id_property_id_fk": { + "name": "property_tag_property_id_property_id_fk", + "tableFrom": "property_tag", + "tableTo": "property", + "columnsFrom": [ + "property_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "property_tag_tag_id_portfolio_tag_id_fk": { + "name": "property_tag_tag_id_portfolio_tag_id_fk", + "tableFrom": "property_tag", + "tableTo": "portfolio_tag", + "columnsFrom": [ + "tag_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "property_tag_property_id_tag_id_pk": { + "name": "property_tag_property_id_tag_id_pk", + "columns": [ + "property_id", + "tag_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sub_task": { + "name": "sub_task", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "task_id": { + "name": "task_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "job_started": { + "name": "job_started", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "job_completed": { + "name": "job_completed", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'In Progress'" + }, + "service": { + "name": "service", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "inputs": { + "name": "inputs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "outputs": { + "name": "outputs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cloud_logs_url": { + "name": "cloud_logs_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "sub_task_task_id_tasks_id_fk": { + "name": "sub_task_task_id_tasks_id_fk", + "tableFrom": "sub_task", + "tableTo": "tasks", + "columnsFrom": [ + "task_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tasks": { + "name": "tasks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "task_source": { + "name": "task_source", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "job_started": { + "name": "job_started", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "job_completed": { + "name": "job_completed", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'In Progress'" + }, + "service": { + "name": "service", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "source", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "source_id": { + "name": "source_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "inputs": { + "name": "inputs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team": { + "name": "team", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "uuid", + "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": { + "team_org_id_organisation_id_fk": { + "name": "team_org_id_organisation_id_fk", + "tableFrom": "team", + "tableTo": "organisation", + "columnsFrom": [ + "org_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_members": { + "name": "team_members", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "team_id": { + "name": "team_id", + "type": "uuid", + "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": { + "team_members_user_id_user_id_fk": { + "name": "team_members_user_id_user_id_fk", + "tableFrom": "team_members", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "team_members_team_id_team_id_fk": { + "name": "team_members_team_id_team_id_fk", + "tableFrom": "team_members", + "tableTo": "team", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.team_portfolio_permissions": { + "name": "team_portfolio_permissions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "team_id": { + "name": "team_id", + "type": "uuid", + "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": { + "team_portfolio_permissions_team_id_team_id_fk": { + "name": "team_portfolio_permissions_team_id_team_id_fk", + "tableFrom": "team_portfolio_permissions", + "tableTo": "team", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "team_portfolio_permissions_portfolio_id_portfolio_id_fk": { + "name": "team_portfolio_permissions_portfolio_id_portfolio_id_fk", + "tableFrom": "team_portfolio_permissions", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.uploaded_files": { + "name": "uploaded_files", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "s3_file_bucket": { + "name": "s3_file_bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "s3_file_key": { + "name": "s3_file_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "s3_upload_timestamp": { + "name": "s3_upload_timestamp", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "landlord_property_id": { + "name": "landlord_property_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uprn": { + "name": "uprn", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "hubspot_listing_id": { + "name": "hubspot_listing_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "file_type": { + "name": "file_type", + "type": "file_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "file_source": { + "name": "file_source", + "type": "file_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uploaded_by": { + "name": "uploaded_by", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "work_order_id": { + "name": "work_order_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "project_workstream_evidence_requirement_id": { + "name": "project_workstream_evidence_requirement_id", + "type": "bigint", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "uploaded_files_uploaded_by_user_id_fk": { + "name": "uploaded_files_uploaded_by_user_id_fk", + "tableFrom": "uploaded_files", + "tableTo": "user", + "columnsFrom": [ + "uploaded_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "uploaded_files_work_order_id_work_order_id_fk": { + "name": "uploaded_files_work_order_id_work_order_id_fk", + "tableFrom": "uploaded_files", + "tableTo": "work_order", + "columnsFrom": [ + "work_order_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "uploaded_files_project_workstream_evidence_requirement_id_project_workstream_evidence_requirement_id_fk": { + "name": "uploaded_files_project_workstream_evidence_requirement_id_project_workstream_evidence_requirement_id_fk", + "tableFrom": "uploaded_files", + "tableTo": "project_workstream_evidence_requirement", + "columnsFrom": [ + "project_workstream_evidence_requirement_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_defined_deal_measures": { + "name": "user_defined_deal_measures", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "hubspot_deal_id": { + "name": "hubspot_deal_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "measure_name": { + "name": "measure_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "user_defined_deal_measure_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "pushed_at": { + "name": "pushed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "confirmed_in_hubspot_at": { + "name": "confirmed_in_hubspot_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_user_defined_deal_measures_deal_id": { + "name": "idx_user_defined_deal_measures_deal_id", + "columns": [ + { + "expression": "hubspot_deal_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_user_defined_deal_measures_source": { + "name": "idx_user_defined_deal_measures_source", + "columns": [ + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_defined_deal_measures_created_by_user_id_user_id_fk": { + "name": "user_defined_deal_measures_created_by_user_id_user_id_fk", + "tableFrom": "user_defined_deal_measures", + "tableTo": "user", + "columnsFrom": [ + "created_by_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_portfolio_config": { + "name": "user_portfolio_config", + "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 + }, + "starred_at": { + "name": "starred_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "folder_id": { + "name": "folder_id", + "type": "bigint", + "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": { + "idx_user_portfolio_config_folder": { + "name": "idx_user_portfolio_config_folder", + "columns": [ + { + "expression": "folder_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_portfolio_config_user_id_user_id_fk": { + "name": "user_portfolio_config_user_id_user_id_fk", + "tableFrom": "user_portfolio_config", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_portfolio_config_portfolio_id_portfolio_id_fk": { + "name": "user_portfolio_config_portfolio_id_portfolio_id_fk", + "tableFrom": "user_portfolio_config", + "tableTo": "portfolio", + "columnsFrom": [ + "portfolio_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_portfolio_config_folder_owner_fk": { + "name": "user_portfolio_config_folder_owner_fk", + "tableFrom": "user_portfolio_config", + "tableTo": "user_portfolio_folders", + "columnsFrom": [ + "folder_id", + "user_id" + ], + "columnsTo": [ + "id", + "user_id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_portfolio_config_user_portfolio_unique": { + "name": "user_portfolio_config_user_portfolio_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "portfolio_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_portfolio_folders": { + "name": "user_portfolio_folders", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "position": { + "name": "position", + "type": "integer", + "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": { + "idx_user_portfolio_folders_user_position": { + "name": "idx_user_portfolio_folders_user_position", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "position", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_portfolio_folders_user_id_user_id_fk": { + "name": "user_portfolio_folders_user_id_user_id_fk", + "tableFrom": "user_portfolio_folders", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_portfolio_folders_id_user_unique": { + "name": "user_portfolio_folders_id_user_unique", + "nullsNotDistinct": false, + "columns": [ + "id", + "user_id" + ] + } + }, + "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.authRateLimits": { + "name": "authRateLimits", + "schema": "", + "columns": { + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "count": { + "name": "count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "window_start": { + "name": "window_start", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "authRateLimits_scope_key_pk": { + "name": "authRateLimits_scope_key_pk", + "columns": [ + "scope", + "key" + ] + } + }, + "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 + }, + "code_hash": { + "name": "code_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.whlg": { + "name": "whlg", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "postcode": { + "name": "postcode", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.aspect_type": { + "name": "aspect_type", + "schema": "public", + "values": [ + "material", + "condition", + "type", + "area", + "configuration", + "presence", + "risk", + "severity", + "location", + "finish", + "insulation", + "pointing", + "spalling", + "lintels", + "cladding", + "category", + "quantity", + "adequacy", + "rating", + "strategy", + "extent", + "distribution", + "structure", + "covering", + "fire_rating", + "external_decoration", + "work_required", + "age_band", + "construction_type", + "classification", + "system" + ] + }, + "public.element_type": { + "name": "element_type", + "schema": "public", + "values": [ + "property", + "property_construction_type", + "property_classification", + "property_age_band", + "storey_count", + "floor_level", + "floor_level_front_door", + "accessible_housing_register", + "asbestos", + "quality_standard", + "ccu", + "passenger_lift", + "stairlift", + "disabled_hoist_tracking", + "disabled_facilities", + "steps_to_front_door", + "roof", + "pitched_roof_covering", + "flat_roof_covering", + "rainwater_goods", + "loft_insulation", + "porch_canopy", + "chimney", + "fascia", + "soffit", + "fascia_soffit_bargeboards", + "gutters", + "store_roof", + "garage_roof", + "garage_and_store_roof", + "external_wall", + "external_noise_insulation", + "primary_wall", + "secondary_wall", + "downpipes", + "external_decoration", + "cladding", + "spandrel_panels", + "garage_walls", + "party_wall_fire_break", + "external_brickwork_pointing", + "internal_downpipes_external_area", + "external_windows", + "communal_windows", + "secondary_glazing", + "store_windows", + "garage_windows", + "garage_and_store_windows", + "external_door", + "front_door", + "rear_door", + "store_door", + "garage_door", + "garage_and_store_door", + "communal_entrance_door", + "main_door", + "block_entrance_door", + "lintel", + "patio_french_door", + "door_entry_handset", + "paths_and_hardstandings", + "parking_areas", + "boundary_walls", + "front_fencing", + "rear_fencing", + "side_fencing", + "rear_gate", + "front_gate", + "gates", + "retaining_walls", + "private_balcony", + "balcony_balustrade", + "outbuildings", + "garage_structure", + "paving", + "roads", + "soil_and_vent", + "solar_thermals", + "drop_kerb", + "outbuilding_overhaul", + "external_structural_defects", + "access_ramp", + "kitchen", + "kitchen_space_layout", + "tenant_installed_kitchen", + "kitchen_extractor_fan", + "bathroom", + "secondary_bathroom", + "secondary_toilet", + "bathroom_extractor_fan", + "additional_wc_or_whb", + "bathroom_remaining_life_source", + "kitchen_remaining_life_source", + "central_heating", + "heating_boiler", + "heating_distribution", + "secondary_heating", + "hot_water_system", + "cold_water_storage", + "heating_system", + "boiler_fuel", + "water_heating", + "programmable_heating", + "community_heating", + "gas_available", + "heat_recovery_units", + "heating_improvements", + "electrical_wiring", + "consumer_unit", + "smoke_detection", + "heat_detection", + "carbon_monoxide_detection", + "fire_door_rating", + "fire_risk_assessment", + "internal_wiring", + "electrics", + "communal_heating", + "communal_boiler", + "communal_electrics", + "communal_fire_alarm", + "communal_emergency_lighting", + "communal_door_entry", + "communal_cctv", + "communal_bin_store", + "communal_bin_store_doors", + "communal_bin_store_walls", + "communal_bin_store_roof", + "communal_refuse_chute", + "communal_floor_covering", + "communal_kitchen", + "communal_bathroom", + "communal_toilets", + "communal_gates", + "communal_lift", + "communal_passenger_lift", + "communal_balcony_walkway", + "communal_entrance", + "communal_internal_decorations", + "communal_internal_floor", + "communal_walkways", + "communal_external_doors", + "communal_stairs", + "communal_aerial", + "communal_aov", + "communal_internal_doors", + "communal_lateral_mains", + "communal_lighting", + "communal_lighting_conductor", + "communal_store_roof", + "communal_store_walls", + "communal_store_doors", + "communal_warden_call_system", + "communal_bms", + "communal_booster_pump", + "communal_dry_riser", + "communal_wet_riser", + "communal_cold_water_storage", + "communal_sprinkler", + "communal_plug_sockets", + "communal_circulation_space", + "ffhh_damp", + "ffhh_hold_and_cold_water", + "ffhh_drainage_lavatories", + "ffhh_neglected", + "ffhh_natural_light", + "ffhh_ventilation", + "ffhh_food_prep_and_washup", + "ffhh_unsafe_layout", + "ffhh_unstable_building", + "hhsrs_damp_and_mould", + "hhsrs_excess_cold", + "hhsrs_excess_heat", + "hhsrs_asbestos_and_mmf", + "hhsrs_biocides", + "hhsrs_carbon_monoxide", + "hhsrs_lead", + "hhsrs_radiation", + "hhsrs_uncombusted_fuel_gas", + "hhsrs_volatile_organic_compounds", + "hhsrs_crowding_and_space", + "hhsrs_entry_by_intruders", + "hhsrs_lighting", + "hhsrs_noise", + "hhsrs_domestic_hygiene_pests_refuse", + "hhsrs_food_safety", + "hhsrs_personal_hygiene_sanitation", + "hhsrs_water_supply", + "hhsrs_falls_associated_with_baths", + "hhsrs_falls_on_level_surfaces", + "hhsrs_falls_on_stairs", + "hhsrs_falls_between_levels", + "hhsrs_electrical_hazards", + "hhsrs_fire", + "hhsrs_flames_hot_surfaces", + "hhsrs_collision_and_entrapment", + "hhsrs_collision_hazards_low_headroom", + "hhsrs_explosions", + "hhsrs_ergonomics", + "hhsrs_structural_collapse", + "hhsrs_amenities" + ] + }, + "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.inspection_archetype_2": { + "name": "inspection_archetype_2", + "schema": "public", + "values": [ + "detached", + "mid-terrace", + "enclosed mid-terrace", + "end-terrace", + "enclosed end-terrace", + "semi-detached" + ] + }, + "public.inspection_archetype": { + "name": "inspection_archetype", + "schema": "public", + "values": [ + "Bungalow", + "Flat", + "Maisonette", + "House", + "non-domestic" + ] + }, + "public.inspection_borescoped": { + "name": "inspection_borescoped", + "schema": "public", + "values": [ + "yes", + "no", + "refused" + ] + }, + "public.inspections_access_issues": { + "name": "inspections_access_issues", + "schema": "public", + "values": [ + "see notes", + "damp issues", + "foliage on walls", + "bushes against wall", + "trees around/anove property", + "high rise block flats/maisonettes", + "conservatory", + "lean-to", + "garage", + "extension", + "decking", + "shed against wall" + ] + }, + "public.inspections_cladding": { + "name": "inspections_cladding", + "schema": "public", + "values": [ + "none", + "cladded with “sufficient space to fill the wall”", + "cladded with “insufficient space to fill the wall”" + ] + }, + "public.inspections_insulation_material": { + "name": "inspections_insulation_material", + "schema": "public", + "values": [ + "empty 50-90", + "empty 100+", + "empty 30-40", + "empty less than 30", + "loose fibre/wool", + "eps/celo/king", + "fibre batts - with cavity", + "fibre batts - no cavity", + "loose bead", + "glued bead", + "formaldehyde", + "bubble wrap", + "poly chunks" + ] + }, + "public.inspections_rendered": { + "name": "inspections_rendered", + "schema": "public", + "values": [ + "no render", + "rendered with “insufficient” space between dpc and render", + "rendered with “sufficient” space between dpc and render" + ] + }, + "public.inspections_roof_orientation": { + "name": "inspections_roof_orientation", + "schema": "public", + "values": [ + "north", + "east", + "south", + "west", + "north-east", + "north-west", + "south-east", + "south-west", + "n/s split", + "e/w split", + "ne/sw split", + "nw/se split", + "flat roof", + "no roof", + "roof too small", + "already has solar pv" + ] + }, + "public.inspections_tile_hung": { + "name": "inspections_tile_hung", + "schema": "public", + "values": [ + "yes", + "no", + "first floor flats are tile hung" + ] + }, + "public.inspections_wall_construction": { + "name": "inspections_wall_construction", + "schema": "public", + "values": [ + "cavity", + "solid", + "system built", + "timber framed", + "steel framed", + "re-walled cavity", + "mansard pre-fab", + "mansard ewi", + "mansard re-walled" + ] + }, + "public.inspections_wall_insulation": { + "name": "inspections_wall_insulation", + "schema": "public", + "values": [ + "empty cavity", + "filled at build", + "partial", + "retro drilled", + "ewi", + "iwi", + "solid non-cavity", + "system built", + "timber framed", + "steel framed" + ] + }, + "public.built_form_type": { + "name": "built_form_type", + "schema": "public", + "values": [ + "Detached", + "Semi-Detached", + "Mid-Terrace", + "End-Terrace", + "Enclosed Mid-Terrace", + "Enclosed End-Terrace", + "Not Recorded", + "Unknown" + ] + }, + "public.construction_age_band": { + "name": "construction_age_band", + "schema": "public", + "values": [ + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "Unknown" + ] + }, + "public.glazing": { + "name": "glazing", + "schema": "public", + "values": [ + "Single glazing", + "Double glazing, 2002 or later", + "Double glazing, pre-2002", + "Triple glazing, pre-2002", + "Triple glazing, 2002 or later", + "Mixed glazing", + "Secondary glazing", + "Unknown" + ] + }, + "public.main_fuel": { + "name": "main_fuel", + "schema": "public", + "values": [ + "mains gas", + "mains gas (community)", + "electricity", + "electricity (community)", + "LPG (bulk)", + "bottled LPG", + "LPG special condition", + "oil", + "house coal", + "smokeless coal", + "dual fuel (mineral and wood)", + "biomass (community)", + "wood logs", + "Unknown" + ] + }, + "public.main_heating_system": { + "name": "main_heating_system", + "schema": "public", + "values": [ + "Gas boiler, combi", + "Gas boiler, regular", + "Gas CPSU", + "Oil boiler, regular", + "Oil boiler, combi", + "Solid fuel boiler", + "Electric storage heaters, old", + "Electric storage heaters, slimline", + "Electric storage heaters, convector", + "Electric storage heaters, fan", + "Direct-acting electric", + "Electric room heaters", + "Solid fuel room heater, closed", + "Air source heat pump", + "Community heating, boilers", + "Community heating, CHP and boilers", + "Oil room heater, 2000 or later", + "Gas room heater, condensing fire", + "Gas room heater, decorative fuel-effect", + "Gas room heater, flush live-effect", + "Gas room heater, open flue 1980 or later", + "Gas room heater, open flue pre-1980", + "Electric storage heaters, high heat retention", + "Solid fuel room heater, open fire", + "Solid fuel room heater, open fire with back boiler", + "Solid fuel room heater, closed with boiler", + "Electric boiler", + "Electric CPSU", + "Electric underfloor, in concrete slab (off-peak)", + "Electric underfloor, integrated storage and direct-acting", + "Electric underfloor, in screed above insulation", + "Unknown" + ] + }, + "public.override_source": { + "name": "override_source", + "schema": "public", + "values": [ + "classifier", + "user", + "os_places" + ] + }, + "public.property_type": { + "name": "property_type", + "schema": "public", + "values": [ + "House", + "Bungalow", + "Flat", + "Maisonette", + "Park home", + "Unknown" + ] + }, + "public.roof_type": { + "name": "roof_type", + "schema": "public", + "values": [ + "Flat, insulated", + "Flat, insulated (assumed)", + "Flat, limited insulation", + "Flat, limited insulation (assumed)", + "Flat, no insulation", + "Flat, no insulation (assumed)", + "Flat, 12 mm insulation", + "Flat, 25 mm insulation", + "Flat, 50 mm insulation", + "Flat, 75 mm insulation", + "Flat, 100 mm insulation", + "Flat, 125 mm insulation", + "Flat, 150 mm insulation", + "Flat, 175 mm insulation", + "Flat, 200 mm insulation", + "Flat, 225 mm insulation", + "Flat, 250 mm insulation", + "Flat, 270 mm insulation", + "Flat, 300 mm insulation", + "Flat, 350 mm insulation", + "Flat, 400 mm insulation", + "Flat, 400+ mm insulation", + "Pitched, insulated", + "Pitched, insulated (assumed)", + "Pitched, insulated at rafters", + "Pitched, limited insulation", + "Pitched, limited insulation (assumed)", + "Pitched, no insulation", + "Pitched, no insulation (assumed)", + "Pitched, Unknown loft insulation", + "Pitched, 0 mm loft insulation", + "Pitched, 12 mm loft insulation", + "Pitched, 25 mm loft insulation", + "Pitched, 50 mm loft insulation", + "Pitched, 75 mm loft insulation", + "Pitched, 100 mm loft insulation", + "Pitched, 125 mm loft insulation", + "Pitched, 150 mm loft insulation", + "Pitched, 175 mm loft insulation", + "Pitched, 200 mm loft insulation", + "Pitched, 225 mm loft insulation", + "Pitched, 250 mm loft insulation", + "Pitched, 270 mm loft insulation", + "Pitched, 300 mm loft insulation", + "Pitched, 350 mm loft insulation", + "Pitched, 400 mm loft insulation", + "Pitched, 400+ mm loft insulation", + "Pitched, sloping ceiling, as built", + "Pitched, sloping ceiling, 12 mm insulation", + "Pitched, sloping ceiling, 25 mm insulation", + "Pitched, sloping ceiling, 50 mm insulation", + "Pitched, sloping ceiling, 75 mm insulation", + "Pitched, sloping ceiling, 100 mm insulation", + "Pitched, sloping ceiling, 125 mm insulation", + "Pitched, sloping ceiling, 150 mm insulation", + "Pitched, sloping ceiling, 175 mm insulation", + "Pitched, sloping ceiling, 200 mm insulation", + "Pitched, sloping ceiling, 225 mm insulation", + "Pitched, sloping ceiling, 250 mm insulation", + "Pitched, sloping ceiling, 270 mm insulation", + "Pitched, sloping ceiling, 300 mm insulation", + "Pitched, sloping ceiling, 350 mm insulation", + "Pitched, sloping ceiling, 400 mm insulation", + "Pitched, sloping ceiling, 400+ mm insulation", + "Roof room(s), insulated", + "Roof room(s), insulated (assumed)", + "Roof room(s), limited insulation", + "Roof room(s), limited insulation (assumed)", + "Roof room(s), no insulation", + "Roof room(s), no insulation (assumed)", + "Roof room(s), ceiling insulated", + "Roof room(s), thatched", + "Roof room(s), thatched with additional insulation", + "Thatched", + "Thatched, with additional insulation", + "(another dwelling above)", + "(same dwelling above)", + "(other premises above)", + "(another premises above)", + "Another Premises Above", + "Unknown" + ] + }, + "public.wall_type": { + "name": "wall_type", + "schema": "public", + "values": [ + "Cavity wall, filled cavity", + "Cavity wall, as built, insulated (assumed)", + "Cavity wall, as built, no insulation (assumed)", + "Cavity wall, as built, partial insulation (assumed)", + "Cavity wall, with internal insulation", + "Cavity wall, with external insulation", + "Cavity wall, filled cavity and internal insulation", + "Cavity wall, filled cavity and external insulation", + "Solid brick, as built, no insulation (assumed)", + "Solid brick, as built, insulated (assumed)", + "Solid brick, as built, partial insulation (assumed)", + "Solid brick, with internal insulation", + "Solid brick, with external insulation", + "Timber frame, as built, no insulation (assumed)", + "Timber frame, as built, insulated (assumed)", + "Timber frame, as built, partial insulation (assumed)", + "Timber frame, with additional insulation", + "Sandstone, as built, no insulation (assumed)", + "Sandstone, as built, insulated (assumed)", + "Sandstone, as built, partial insulation (assumed)", + "Sandstone, with internal insulation", + "Sandstone, with external insulation", + "Granite or whin, as built, no insulation (assumed)", + "Granite or whin, as built, insulated (assumed)", + "Granite or whin, as built, partial insulation (assumed)", + "Granite or whin, with internal insulation", + "Granite or whin, with external insulation", + "System built, as built, no insulation (assumed)", + "System built, as built, insulated (assumed)", + "System built, as built, partial insulation (assumed)", + "System built, with internal insulation", + "System built, with external insulation", + "Park home wall, as built", + "Park home wall, with internal insulation", + "Park home wall, with external insulation", + "Cob, as built", + "Cob, with internal insulation", + "Cob, with external insulation", + "Curtain wall", + "Curtain Wall, as built, no insulation (assumed)", + "Curtain Wall, as built, insulated (assumed)", + "Curtain Wall, filled cavity", + "Curtain Wall, with internal insulation", + "Basement wall", + "Basement wall, as built", + "Unknown" + ] + }, + "public.water_heating": { + "name": "water_heating", + "schema": "public", + "values": [ + "From main system, mains gas", + "From main system, electricity", + "From main system, oil", + "From main system, LPG (bulk)", + "From main system, bottled LPG", + "From main system, house coal", + "Electric immersion, electricity", + "Gas boiler/circulator, mains gas", + "From main system, wood logs", + "From main system, biomass (community)", + "From main system, dual fuel (mineral and wood)", + "From main system, biodiesel (community)", + "Unknown" + ] + }, + "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", + "secondary_glazing", + "double_glazing", + "trickle_vent", + "door_undercut", + "solar_pv", + "solar_battery", + "scaffolding", + "high_heat_retention_storage_heaters", + "air_source_heat_pump", + "boiler_upgrade", + "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.portfolio_capability": { + "name": "portfolio_capability", + "schema": "public", + "values": [ + "approver", + "contractor" + ] + }, + "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.override_component": { + "name": "override_component", + "schema": "public", + "values": [ + "wall_type", + "roof_type", + "property_type", + "built_form_type", + "main_fuel", + "glazing", + "construction_age_band", + "water_heating", + "main_heating_system" + ] + }, + "public.energy_element_type": { + "name": "energy_element_type", + "schema": "public", + "values": [ + "roof", + "wall", + "floor", + "main_heating", + "window", + "lighting", + "hot_water", + "secondary_heating", + "main_heating_controls" + ] + }, + "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.rebaseline_reason": { + "name": "rebaseline_reason", + "schema": "public", + "values": [ + "none", + "pre_sap10", + "physical_state_changed", + "both" + ] + }, + "public.housing_type": { + "name": "housing_type", + "schema": "public", + "values": [ + "Private", + "Social" + ] + }, + "public.measure_type": { + "name": "measure_type", + "schema": "public", + "values": [ + "air_source_heat_pump", + "boiler_upgrade", + "high_heat_retention_storage_heaters", + "secondary_heating", + "roomstat_programmer_trvs", + "time_temperature_zone_control", + "cylinder_thermostat", + "cavity_wall_insulation", + "extension_cavity_wall_insulation", + "external_wall_insulation", + "internal_wall_insulation", + "loft_insulation", + "flat_roof_insulation", + "room_roof_insulation", + "solid_floor_insulation", + "suspended_floor_insulation", + "double_glazing", + "secondary_glazing", + "draught_proofing", + "mechanical_ventilation", + "low_energy_lighting", + "solar_pv", + "hot_water_tank_insulation", + "sealing_open_fireplace" + ] + }, + "public.plan_type": { + "name": "plan_type", + "schema": "public", + "values": [ + "solar_eco4", + "solar_hhrsh_eco4", + "empty_cavity_eco", + "partial_cavity_eco", + "extraction_eco" + ] + }, + "public.unit_quantity": { + "name": "unit_quantity", + "schema": "public", + "values": [ + "m2", + "part", + "kwp" + ] + }, + "public.scenario_type": { + "name": "scenario_type", + "schema": "public", + "values": [ + "unit", + "building" + ] + }, + "public.source": { + "name": "source", + "schema": "public", + "values": [ + "portfolio_id", + "hubspot_deal_id", + "property_id" + ] + }, + "public.file_source": { + "name": "file_source", + "schema": "public", + "values": [ + "pas hub", + "sharepoint", + "hubspot", + "ecmk", + "contractor", + "magic_plan", + "coordination_hub", + "audit_generator", + "projects" + ] + }, + "public.file_type": { + "name": "file_type", + "schema": "public", + "values": [ + "photo_pack", + "site_note", + "rd_sap_site_note", + "pas_2023_ventilation", + "pas_2023_condition", + "pas_significance", + "par_photo_pack", + "pas_2023_property", + "pas_2023_occupancy", + "ecmk_site_note", + "ecmk_rd_sap_site_note", + "ecmk_survey_xml", + "pre_photo", + "mid_photo", + "post_photo", + "loft_hatch_photo", + "dmev_photos", + "door_undercut_photos", + "trickle_vent_photos", + "pre_installation_building_inspection", + "point_of_work_risk_assessment", + "claim_of_compliance", + "mcs_compliance_certificate", + "certificate_of_conformity", + "minor_works_electrical_certificate", + "trustmark_licence_numbers", + "operative_competency", + "ventilation_assessment_checklist", + "anemometer_readings", + "commissioning_records", + "part_f_ventilation_document", + "handover_pack", + "insurance_guarantee", + "workmanship_warranty", + "g98_notification", + "installer_qualifications", + "installer_feedback", + "contractor_other", + "magic_plan_json", + "improvement_option_evaluation", + "medium_term_improvement_plan", + "retrofit_design_doc", + "ventilation_audit", + "other" + ] + }, + "public.user_defined_deal_measure_source": { + "name": "user_defined_deal_measure_source", + "schema": "public", + "values": [ + "instructed", + "pibi_ordered" + ] + }, + "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 2b58eb0e..c43181f7 100644 --- a/src/app/db/migrations/meta/_journal.json +++ b/src/app/db/migrations/meta/_journal.json @@ -1926,6 +1926,41 @@ "when": 1784656804281, "tag": "0275_opposite_ronan", "breakpoints": true + }, + { + "idx": 276, + "version": "7", + "when": 1784798917178, + "tag": "0276_romantic_synch", + "breakpoints": true + }, + { + "idx": 277, + "version": "7", + "when": 1784801404980, + "tag": "0277_woozy_prism", + "breakpoints": true + }, + { + "idx": 278, + "version": "7", + "when": 1784810497155, + "tag": "0278_living_baron_strucker", + "breakpoints": true + }, + { + "idx": 279, + "version": "7", + "when": 1784817538731, + "tag": "0279_blushing_mattie_franklin", + "breakpoints": true + }, + { + "idx": 280, + "version": "7", + "when": 1784819275099, + "tag": "0280_flashy_dreadnoughts", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/app/db/schema/landlord_overrides.ts b/src/app/db/schema/landlord_overrides.ts index 7d095735..cace08fb 100644 --- a/src/app/db/schema/landlord_overrides.ts +++ b/src/app/db/schema/landlord_overrides.ts @@ -130,6 +130,30 @@ export const RoofTypeValues: [string, ...string[]] = [ "Pitched, 350 mm loft insulation", "Pitched, 400 mm loft insulation", "Pitched, 400+ mm loft insulation", + // Pitched roof with a sloping ceiling — insulation sits at the rafter/slope + // line, NOT a horizontal loft, so it is modelled explicitly rather than + // flattened onto the "Pitched, N mm loft insulation" ladder. Depth ladder + // mirrors the loft one (12 mm … 400+ mm); "as built" defers the insulation + // assumption to the construction age band. Source EPC field is + // "PitchedWithSlopingCeiling"; this canonical name is intentionally our own. + // See Hestia-Homes/Model#1676 (roof overlay must model these at rafter level). + "Pitched, sloping ceiling, as built", + "Pitched, sloping ceiling, 12 mm insulation", + "Pitched, sloping ceiling, 25 mm insulation", + "Pitched, sloping ceiling, 50 mm insulation", + "Pitched, sloping ceiling, 75 mm insulation", + "Pitched, sloping ceiling, 100 mm insulation", + "Pitched, sloping ceiling, 125 mm insulation", + "Pitched, sloping ceiling, 150 mm insulation", + "Pitched, sloping ceiling, 175 mm insulation", + "Pitched, sloping ceiling, 200 mm insulation", + "Pitched, sloping ceiling, 225 mm insulation", + "Pitched, sloping ceiling, 250 mm insulation", + "Pitched, sloping ceiling, 270 mm insulation", + "Pitched, sloping ceiling, 300 mm insulation", + "Pitched, sloping ceiling, 350 mm insulation", + "Pitched, sloping ceiling, 400 mm insulation", + "Pitched, sloping ceiling, 400+ mm insulation", "Roof room(s), insulated", "Roof room(s), insulated (assumed)", "Roof room(s), limited insulation", @@ -231,6 +255,14 @@ export const MainHeatingSystemValues: [string, ...string[]] = [ "Gas boiler, combi", "Gas boiler, regular", "Gas CPSU", + // Non-gas wet boilers. A fuel-agnostic "Boiler" description defaults to a gas + // archetype, which is wrong when the property's main_fuel is oil or a solid + // fuel — these give the classifier/overlay a correct target. Fuel granularity + // (house coal / wood logs / dual fuel) is carried by the separate `main_fuel` + // column, applied on top of the archetype (ADR-0041). See Hestia-Homes/Model#1676. + "Oil boiler, regular", + "Oil boiler, combi", + "Solid fuel boiler", "Electric storage heaters, old", "Electric storage heaters, slimline", "Electric storage heaters, convector", diff --git a/src/app/db/schema/projects/projects.ts b/src/app/db/schema/projects/projects.ts index 221c0602..dc5293ed 100644 --- a/src/app/db/schema/projects/projects.ts +++ b/src/app/db/schema/projects/projects.ts @@ -7,8 +7,11 @@ // `project_workstream_contractor.organisation_id` are uuid FKs to it. // - Property has a bigint PK (see property.ts), so every `property_id` FK is // bigint, not the integer the doc assumed. -// - status / priority columns whose enum values are still TBC are modelled as -// `text` for now; convert to pgEnum once the value sets are agreed. +// - status columns whose enum values are still TBC are modelled as `text` for +// now; convert to pgEnum once the value sets are agreed. +// - `work_order.priority` started as one of those `text` columns and is now a +// boolean: it turned out to be a flag ("look at this one first"), not a +// scale, so there is no value set left to agree. See CONTEXT.md, "Priority". import { type AnyPgColumn, bigint, @@ -181,7 +184,10 @@ export const workOrder = pgTable("work_order", { // Enum values TBC — modelled as text until the value sets are agreed. status: text("status").notNull(), forecastEnd: date("forecast_end"), - priority: text("priority"), + // A flag, not a scale: a work order either is flagged as priority or is not. + // NOT NULL DEFAULT false because a third "unknown" state has no meaning for a + // flag — the table renders it or renders nothing. + priority: boolean("priority").notNull().default(false), }); export type Project = InferModel; diff --git a/src/app/db/schema/projects/schema.md b/src/app/db/schema/projects/schema.md index 38d5f0ff..11f645b2 100644 --- a/src/app/db/schema/projects/schema.md +++ b/src/app/db/schema/projects/schema.md @@ -66,9 +66,13 @@ Project > optional evidence-requirement link) carries this. > - **Property has a `bigint` PK** (`bigserial`), not an integer one. Every > `property_id` FK is `bigint`. -> - **`status` / `priority` columns are `text` for now**, not Postgres enums — -> their value sets are still TBC and an empty enum can't be created. Convert to -> `pgEnum` once the values are agreed. +> - **`status` columns are `text` for now**, not Postgres enums — their value +> sets are still TBC and an empty enum can't be created. Convert to `pgEnum` +> once the values are agreed. +> - **`work_order.priority` is a `boolean`**, not one of those `text` columns. +> It is a flag ("look at this one first"), not a scale, so no value set was +> ever needed. Changed under #419, when the admin work-orders table surfaced +> it as a column. > - **No new `uploaded_by` column** on `uploaded_files`; the existing > `uploaded_by` `bigint` FK → user is reused. > - **No `document_type` table.** Evidence requirements reference the existing @@ -256,7 +260,7 @@ Represents work issued to a contractor. | project_workstream_stage_id | bigint | No | FK → Project Workstream Stage | | status | text | No | Values TBC — `text` for now, convert to Postgres enum once agreed | | forecast_end | date | Yes | | -| priority | text | Yes | Values TBC — `text` for now, convert to Postgres enum once agreed | +| priority | boolean | No | Flag, not a scale — "look at this one first". Default `false` | --- diff --git a/src/app/db/schema/property.ts b/src/app/db/schema/property.ts index 6e614d8d..35d3f1a7 100644 --- a/src/app/db/schema/property.ts +++ b/src/app/db/schema/property.ts @@ -583,6 +583,7 @@ export const epcProperty = pgTable( heatingSecondaryHeatingType: jsonb("heating_secondary_heating_type"), heatingCylinderInsulationThicknessMm: integer("heating_cylinder_insulation_thickness_mm"), heatingCylinderVolumeMeasuredL: integer("heating_cylinder_volume_measured_l"), // litres, nullable + heatingCylinderHeatLoss: doublePrecision("heating_cylinder_heat_loss"), // nullable heatingWwhrsIndexNumber1: integer("heating_wwhrs_index_number_1"), heatingWwhrsIndexNumber2: integer("heating_wwhrs_index_number_2"), heatingShowerOutletType: jsonb("heating_shower_outlet_type"), @@ -799,10 +800,17 @@ export const epcBuildingPart = pgTable( // the result: a system-built wall bills as a basement wall, and via has_basement // drags the whole ground floor onto the Table 23 basement-floor U-value. wallIsBasement: boolean("wall_is_basement"), + // Lodged gov-EPC wall U-value. Unlike the columns dropped in #1661, the + // calculator now honours this over the derived construction-default (#1665). + // Nullable: null means "not lodged → the calculator derives it". double + // precision to match the other new #1665 floats and keep the round-trip exact. + wallUValue: doublePrecision("wall_u_value"), - // Room in roof (inlined) - roomInRoofFloorArea: real("room_in_roof_floor_area"), - roomInRoofConstructionAgeBand: text("room_in_roof_construction_age_band"), + // Room-in-roof geometry now lives in the epc_room_in_roof / + // epc_room_in_roof_surface child tables (Model #1665). The two flattened + // columns that used to sit here (room_in_roof_floor_area, + // room_in_roof_construction_age_band) were dropped as their redundant + // duplicates. // Alternative wall 1 (inlined) altWall1Area: real("alt_wall_1_area"), @@ -812,6 +820,12 @@ export const epcBuildingPart = pgTable( altWall1ThicknessMeasured: text("alt_wall_1_thickness_measured"), altWall1InsulationThickness: text("alt_wall_1_insulation_thickness"), altWall1IsSheltered: boolean("alt_wall_1_is_sheltered"), // nullable (null when no alt wall) + altWall1UValue: doublePrecision("alt_wall_1_u_value"), // nullable + altWall1ThicknessMm: integer("alt_wall_1_thickness_mm"), // nullable + // NULLABLE, load-bearing — do NOT make it notNull().default(false). null "not + // stated" vs false "explicitly not a basement" are distinct; collapsing them + // re-enables the code-6 basement heuristic this flag exists to defeat. + altWall1IsBasement: boolean("alt_wall_1_is_basement"), // Alternative wall 2 (inlined) altWall2Area: real("alt_wall_2_area"), @@ -821,6 +835,10 @@ export const epcBuildingPart = pgTable( altWall2ThicknessMeasured: text("alt_wall_2_thickness_measured"), altWall2InsulationThickness: text("alt_wall_2_insulation_thickness"), altWall2IsSheltered: boolean("alt_wall_2_is_sheltered"), // nullable (null when no alt wall) + altWall2UValue: doublePrecision("alt_wall_2_u_value"), // nullable + altWall2ThicknessMm: integer("alt_wall_2_thickness_mm"), // nullable + // NULLABLE, load-bearing — see altWall1IsBasement above. + altWall2IsBasement: boolean("alt_wall_2_is_basement"), }, (table) => [ // Per-EPC part lookups: the reporting age-band subquery and the @@ -856,6 +874,84 @@ export const epcFloorDimension = pgTable( ], ); +// ─── epc_roof_window ────────────────────────────────────────────────────────── +// 0..n per epc_property. No explicit onDelete: matches every existing EPC child +// FK (epc_photovoltaic_array, epc_window, …) — the Python backend owns these +// tables and rewrites children by delete-and-reinsert on re-ingest. + +export const epcRoofWindow = pgTable( + "epc_roof_window", + { + id: bigserial("id", { mode: "bigint" }).primaryKey(), + epcPropertyId: bigint("epc_property_id", { mode: "bigint" }) + .notNull() + .references(() => epcProperty.id), + + roofWindowIndex: integer("roof_window_index").notNull(), // preserves list order for round-trip + areaM2: doublePrecision("area_m2").notNull(), + uValueRaw: doublePrecision("u_value_raw").notNull(), // Table 24 roof-window U, pre-curtain + orientation: integer("orientation").notNull(), // SAP orientation code + pitchDeg: doublePrecision("pitch_deg").notNull(), + gPerpendicular: doublePrecision("g_perpendicular").notNull(), + frameFactor: doublePrecision("frame_factor").notNull(), + glazingType: integer("glazing_type").notNull(), // SAP Table U2 code + windowLocation: jsonb("window_location").notNull(), // int (API) or str (site-notes) — jsonb preserves type + }, + (t) => [ + uniqueIndex("uq_epc_roof_window_property_index").on(t.epcPropertyId, t.roofWindowIndex), + ], +); + +// ─── epc_room_in_roof ───────────────────────────────────────────────────────── +// 0..1 per epc_building_part. Supersedes the inlined room_in_roof_floor_area / +// room_in_roof_construction_age_band columns on epc_building_part, which are left +// in place here and dropped in a follow-up migration (see Model #1665). + +export const epcRoomInRoof = pgTable( + "epc_room_in_roof", + { + id: bigserial("id", { mode: "bigint" }).primaryKey(), + epcBuildingPartId: bigint("epc_building_part_id", { mode: "bigint" }) + .notNull() + .unique() // 0..1 per part + .references(() => epcBuildingPart.id), + + floorArea: doublePrecision("floor_area").notNull(), + constructionAgeBand: text("construction_age_band").notNull(), + commonWallLengthM: doublePrecision("common_wall_length_m"), // nullable + commonWallHeightM: doublePrecision("common_wall_height_m"), // nullable + gable1LengthM: doublePrecision("gable_1_length_m"), // nullable + gable1HeightM: doublePrecision("gable_1_height_m"), // nullable + gable2LengthM: doublePrecision("gable_2_length_m"), // nullable + gable2HeightM: doublePrecision("gable_2_height_m"), // nullable + }, +); + +// ─── epc_room_in_roof_surface ───────────────────────────────────────────────── + +export const epcRoomInRoofSurface = pgTable( + "epc_room_in_roof_surface", + { + id: bigserial("id", { mode: "bigint" }).primaryKey(), + epcRoomInRoofId: bigint("epc_room_in_roof_id", { mode: "bigint" }) + .notNull() + .references(() => epcRoomInRoof.id), + + surfaceIndex: integer("surface_index").notNull(), // preserves list order + // slope|flat_ceiling|stud_wall|gable_wall|gable_wall_external|gable_wall_sheltered + // |common_wall|connected_wall — TEXT, not a pg enum (the set has grown twice). + kind: text("kind").notNull(), + areaM2: doublePrecision("area_m2").notNull(), // CAN BE NEGATIVE (signed §3.9.2 adjustment) — no CHECK >= 0 + // NULLABLE — null vs 0 is the U-value branch (Table 17 vs default). + insulationThicknessMm: integer("insulation_thickness_mm"), + insulationType: text("insulation_type"), // nullable: mineral_wool|eps|pur|pir + uValue: doublePrecision("u_value"), // NULLABLE — assessor U override; null ≠ 0 + }, + (t) => [ + uniqueIndex("uq_epc_room_in_roof_surface_index").on(t.epcRoomInRoofId, t.surfaceIndex), + ], +); + // ─── epc_window ─────────────────────────────────────────────────────────────── export const epcWindow = pgTable( diff --git a/src/app/db/seed/seed-projects-dashboard.ts b/src/app/db/seed/seed-projects-dashboard.ts new file mode 100644 index 00000000..1d8c017c --- /dev/null +++ b/src/app/db/seed/seed-projects-dashboard.ts @@ -0,0 +1,244 @@ +/** + * Programme-dashboard load fixture (issue #418). + * + * Seeds one Ara Project with ~1,500 work orders spread across workstreams, + * stages, contractors and forecast dates, so a human can check that + * `/projects/[projectId]` renders acceptably at programme scale — the issue's + * acceptance criterion. + * + * ## THIS SCRIPT WAS NEVER RUN + * + * It is deliberately shipped unexecuted. The `DATABASE_URL` available while + * this issue was implemented points at the **production** database — one + * database shared by the deployed site and every dev environment — so seeding + * 1,500 synthetic work orders from here would have written fabricated delivery + * records into live data. Run it yourself, against a non-production database. + * + * ## Running it + * + * ALLOW_PROJECTS_DASHBOARD_SEED=i-am-not-production \ + * npx tsx src/app/db/seed/seed-projects-dashboard.ts + * + * The guard below refuses to do anything without that variable, and refuses + * outright when `NODE_ENV=production`. It is a speed bump, not a safety net: + * the only real protection is pointing `DB_HOST` somewhere disposable. Check + * `DB_HOST` before you run it — the script prints it and pauses. + * + * Everything it writes is prefixed `SEED-418-` (work-order references) or named + * `[seed-418] …`, so it can be found and removed again: + * + * DELETE FROM work_order WHERE reference LIKE 'SEED-418-%'; + * + * The project itself must already exist, along with at least one Property + * linked to it via `project_property` and one `organisation` to act as + * contractor; the script reuses those rather than inventing properties. + */ +import { eq } from "drizzle-orm"; +import { db, pool } from "@/app/db/db"; +import { + project, + projectProperty, + projectWorkstream, + projectWorkstreamContractor, + projectWorkstreamStage, + workOrder, + workstream, +} from "@/app/db/schema/projects/projects"; +import { organisation } from "@/app/db/schema/organisation"; + +/** Total work orders to create — the scale the acceptance criterion names. */ +const TARGET_WORK_ORDERS = 1500; + +/** The v1 default ladder (CONTEXT.md, "Stage"). Terminal = highest `order`. */ +const STAGE_LADDER = [ + "Ordered", + "In progress", + "Completed", + "Charged", + "Closed", +] as const; + +/** Workstreams to instantiate, by `workstream.name` in the reference data. */ +const WORKSTREAM_NAMES = [ + "Windows", + "Doors", + "Roofs", + "Electrical", + "Heating", +] as const; + +/** How many contractor organisations to spread the work across. */ +const CONTRACTOR_COUNT = 3; + +async function main() { + assertSeedingIsAllowed(); + + const projectId = readProjectIdArg(); + const [found] = await db + .select({ id: project.id, name: project.name, organisationId: project.organisationId }) + .from(project) + .where(eq(project.id, projectId)) + .limit(1); + if (!found) throw new Error(`No project with id ${projectId}`); + + console.log(`Seeding project ${found.id} ("${found.name}")`); + console.log(` DB_HOST = ${process.env.DB_HOST ?? "(unset)"}`); + console.log(` DB_NAME = ${process.env.DB_NAME ?? "(unset)"}`); + await pause(); + + const propertyIds = ( + await db + .select({ propertyId: projectProperty.propertyId }) + .from(projectProperty) + .where(eq(projectProperty.projectId, projectId)) + ).map((r) => r.propertyId); + if (propertyIds.length === 0) { + throw new Error( + `Project ${projectId} has no properties in project_property — link some first.`, + ); + } + + const contractorOrgIds = ( + await db.select({ id: organisation.id }).from(organisation).limit(CONTRACTOR_COUNT) + ).map((r) => r.id); + if (contractorOrgIds.length === 0) throw new Error("No organisations to use as contractors."); + + const workstreamIds = await resolveWorkstreamReferenceData(); + + // One Project Workstream per reference workstream, each with its own full + // ladder and its own contractor assignments. + const assignments: { stageIds: bigint[]; contractorIds: bigint[] }[] = []; + for (const workstreamId of workstreamIds) { + const [createdWorkstream] = await db + .insert(projectWorkstream) + .values({ projectId, workstreamId }) + .returning({ id: projectWorkstream.id }); + + const stageIds: bigint[] = []; + for (const [index, name] of STAGE_LADDER.entries()) { + const [stage] = await db + .insert(projectWorkstreamStage) + .values({ + projectWorkstreamId: createdWorkstream.id, + name, + order: index + 1, + status: "active", + }) + .returning({ id: projectWorkstreamStage.id }); + stageIds.push(stage.id); + } + + const contractorIds: bigint[] = []; + for (const organisationId of contractorOrgIds) { + const [contractor] = await db + .insert(projectWorkstreamContractor) + .values({ + projectWorkstreamId: createdWorkstream.id, + organisationId, + updateStagesPermission: true, + uploadDocumentsPermission: true, + }) + .returning({ id: projectWorkstreamContractor.id }); + contractorIds.push(contractor.id); + } + + assignments.push({ stageIds, contractorIds }); + } + + // Deterministic spread — no randomness, so two runs of the fixture produce + // the same dashboard and a rendering regression is visible as a diff. + const rows: (typeof workOrder.$inferInsert)[] = []; + for (let i = 0; i < TARGET_WORK_ORDERS; i++) { + const assignment = assignments[i % assignments.length]; + const stageId = assignment.stageIds[i % assignment.stageIds.length]; + const contractorId = assignment.contractorIds[i % assignment.contractorIds.length]; + rows.push({ + reference: `SEED-418-${String(i).padStart(5, "0")}`, + projectWorkstreamContractorId: contractorId, + propertyId: propertyIds[i % propertyIds.length], + projectWorkstreamStageId: stageId, + status: "seeded", + // Every third order sits in the past, so the overdue rule has something + // to find on non-terminal stages — and something to *ignore* on terminal + // ones, which is the case worth eyeballing. + forecastEnd: offsetDay(i % 3 === 0 ? -30 : 30), + }); + } + + // Chunked so the insert does not exceed the parameter limit. + const CHUNK = 500; + for (let i = 0; i < rows.length; i += CHUNK) { + await db.insert(workOrder).values(rows.slice(i, i + CHUNK)); + console.log(` inserted ${Math.min(i + CHUNK, rows.length)}/${rows.length}`); + } + + console.log(`Done. Open /projects/${projectId} and check the render.`); +} + +/** + * Ensure the reference `workstream` rows this fixture needs exist, creating any + * that do not. Reference data proper is #407's job; this only fills gaps so the + * fixture is runnable on a bare database. + */ +async function resolveWorkstreamReferenceData(): Promise { + const ids: bigint[] = []; + for (const name of WORKSTREAM_NAMES) { + const [existing] = await db + .select({ id: workstream.id }) + .from(workstream) + .where(eq(workstream.name, name)) + .limit(1); + if (existing) { + ids.push(existing.id); + continue; + } + const [created] = await db + .insert(workstream) + .values({ name, description: `[seed-418] ${name}` }) + .returning({ id: workstream.id }); + ids.push(created.id); + } + return ids; +} + +/** Refuse to run without an explicit opt-in, and never under NODE_ENV=production. */ +function assertSeedingIsAllowed(): void { + if (process.env.NODE_ENV === "production") { + throw new Error("Refusing to seed: NODE_ENV=production."); + } + if (process.env.ALLOW_PROJECTS_DASHBOARD_SEED !== "i-am-not-production") { + throw new Error( + "Refusing to seed. This writes ~1,500 fabricated work orders.\n" + + "Point DB_HOST at a non-production database, then re-run with\n" + + " ALLOW_PROJECTS_DASHBOARD_SEED=i-am-not-production", + ); + } +} + +function readProjectIdArg(): bigint { + const raw = process.argv[2]; + if (!raw || !/^\d+$/.test(raw)) { + throw new Error("Usage: tsx src/app/db/seed/seed-projects-dashboard.ts "); + } + return BigInt(raw); +} + +/** A `YYYY-MM-DD` day `days` from today, for `work_order.forecast_end`. */ +function offsetDay(days: number): string { + const date = new Date(); + date.setUTCDate(date.getUTCDate() + days); + return date.toISOString().slice(0, 10); +} + +/** Five seconds to read the printed host and hit Ctrl-C. */ +function pause(): Promise { + console.log(" starting in 5s — Ctrl-C now if that is not a scratch database"); + return new Promise((resolve) => setTimeout(resolve, 5000)); +} + +main() + .catch((error) => { + console.error(error instanceof Error ? error.message : error); + process.exitCode = 1; + }) + .finally(() => pool.end()); diff --git a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/[dealId]/page.tsx b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/[dealId]/page.tsx index 18dfe690..b85b3d3a 100644 --- a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/[dealId]/page.tsx +++ b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/[dealId]/page.tsx @@ -13,7 +13,11 @@ import { user as userTable } from "@/app/db/schema/users"; import type { DocStatus, PortfolioCapabilityType } from "../types"; import { deriveEffectiveRemovalState } from "../removalState"; import { classifyDeals } from "../transforms"; -import { fetchDocsByDealId, computeDocStatusMap } from "../docStatus"; +import { + fetchDocsByDealId, + computeDocStatusMap, + deriveDesignDocDealIds, +} from "../docStatus"; import { coordinatorUser, designerUser, mapDbRowToHubspotDeal } from "../dealQuery"; import type { DealRow } from "../dealQuery"; import DealPage from "./DealPage"; @@ -74,7 +78,13 @@ export default async function DealDetailPage(props: { } const hubspotDeal = mapDbRowToHubspotDeal(rawDeals[0]); - const [deal] = classifyDeals([hubspotDeal]); + + // Fetch this deal's documents before classifying so Retrofit Design Document + // presence drives the Design-vs-Installation boundary, consistent with the + // Live projects list. The same documents feed the document-status map below. + const docsByDealId = await fetchDocsByDealId([hubspotDeal], [dealId]); + const designDocDealIds = deriveDesignDocDealIds(docsByDealId); + const [deal] = classifyDeals([hubspotDeal], designDocDealIds); const userEmail = session.user.email; let userCapability: PortfolioCapabilityType = []; @@ -151,7 +161,6 @@ export default async function DealDetailPage(props: { ? deriveEffectiveRemovalState(removalRows[0]) : "none"; - const docsByDealId = await fetchDocsByDealId([hubspotDeal], [dealId]); const docStatusMap = computeDocStatusMap([hubspotDeal], docsByDealId, { [dealId]: approvedMeasures }); const docStatus: DocStatus = docStatusMap[dealId] ?? { presentSurveyTypes: [], diff --git a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/docStatus.test.ts b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/docStatus.test.ts index cd2c1d08..45eed2f3 100644 --- a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/docStatus.test.ts +++ b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/docStatus.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from "vitest"; -import { computeDocStatusMap } from "./docStatus"; +import { computeDocStatusMap, deriveDesignDocDealIds } from "./docStatus"; import { EXPECTED_RETROFIT_ASSESSMENT_DOC_TYPES } from "./types"; import type { HubspotDeal, ApprovalsByDeal } from "./types"; @@ -81,6 +81,40 @@ const allSurveyDocs = EXPECTED_RETROFIT_ASSESSMENT_DOC_TYPES.map((t) => ({ measureName: null, })); +describe("deriveDesignDocDealIds", () => { + it("includes a deal that holds a Retrofit Design Document", () => { + // Arrange + const docsByDealId = new Map([ + ["deal-1", [{ fileType: "retrofit_design_doc", measureName: null }]], + ]); + + // Act + const designDocDealIds = deriveDesignDocDealIds(docsByDealId); + + // Assert + expect(designDocDealIds.has("deal-1")).toBe(true); + }); + + it("excludes a deal whose documents contain no Retrofit Design Document", () => { + // Arrange — only survey/install docs, no design document + const docsByDealId = new Map([ + [ + "deal-1", + [ + { fileType: "photo_pack", measureName: null }, + { fileType: "pre_photo", measureName: "CWI" }, + ], + ], + ]); + + // Act + const designDocDealIds = deriveDesignDocDealIds(docsByDealId); + + // Assert + expect(designDocDealIds.has("deal-1")).toBe(false); + }); +}); + describe("computeDocStatusMap", () => { it("marks survey as complete when all 9 mandatory doc types are present", () => { const deal = makeDeal({ dealId: "deal-1" }); @@ -123,6 +157,19 @@ describe("computeDocStatusMap", () => { expect(measureNames).not.toContain("CWI"); }); + it("does not report install documents for a deal holding only a Retrofit Design Document", () => { + // Arrange — a design document is not an install document + const deal = makeDeal({ dealId: "deal-1", proposedMeasures: "CWI" }); + const docs = new Map([["deal-1", [{ fileType: "retrofit_design_doc", measureName: null }]]]); + + // Act + const result = computeDocStatusMap([deal], docs, {}); + + // Assert + expect(result["deal-1"].hasInstallDocs).toBe(false); + expect(result["deal-1"].installStatus).toBe("none"); + }); + describe("installStatus", () => { // CWI requires only BASE_DOCS — simple to satisfy in tests const cwi = "CWI"; @@ -169,6 +216,69 @@ describe("computeDocStatusMap", () => { expect(result["deal-1"].installStatus).toBe("hasDocs"); }); + it('is "none" when the only docs are coordination docs, which the drawer lists separately', () => { + // Arrange + const deal = makeDeal({ dealId: "deal-1", proposedMeasures: null }); + const coordinationDocs = [ + { fileType: "improvement_option_evaluation", measureName: null }, + ]; + const docs = new Map([["deal-1", coordinationDocs]]); + + // Act + const result = computeDocStatusMap([deal], docs, {}); + + // Assert + expect(result["deal-1"].installStatus).toBe("none"); + }); + + it('is "none" when the only docs are design docs, which the drawer lists separately', () => { + // Arrange + const deal = makeDeal({ dealId: "deal-1", proposedMeasures: null }); + const designDocs = [{ fileType: "retrofit_design_doc", measureName: null }]; + const docs = new Map([["deal-1", designDocs]]); + + // Act + const result = computeDocStatusMap([deal], docs, {}); + + // Assert + expect(result["deal-1"].installStatus).toBe("none"); + }); + + it("counts only genuine install docs when coordination and design docs are also present", () => { + // Arrange + const deal = makeDeal({ dealId: "deal-1", proposedMeasures: cwi }); + const mixedDocs = [ + { fileType: "improvement_option_evaluation", measureName: null }, + { fileType: "retrofit_design_doc", measureName: null }, + ...cwiRequiredDocs.map((ft) => ({ fileType: ft, measureName: cwi })), + ]; + const docs = new Map([["deal-1", mixedDocs]]); + + // Act + const result = computeDocStatusMap([deal], docs, {}); + + // Assert + expect(result["deal-1"].measureProgress).toEqual([ + expect.objectContaining({ measureName: cwi, uploadedCount: cwiRequiredDocs.length }), + ]); + }); + + it("reports no install docs when only coordination and design docs are present", () => { + // Arrange + const deal = makeDeal({ dealId: "deal-1", proposedMeasures: null }); + const nonInstallDocs = [ + { fileType: "medium_term_improvement_plan", measureName: null }, + { fileType: "retrofit_design_doc", measureName: null }, + ]; + const docs = new Map([["deal-1", nonInstallDocs]]); + + // Act + const result = computeDocStatusMap([deal], docs, {}); + + // Assert + expect(result["deal-1"].hasInstallDocs).toBe(false); + }); + it('is "none" when measures are defined but no install docs have been uploaded', () => { const deal = makeDeal({ dealId: "deal-1", proposedMeasures: cwi }); // Only survey docs — no install docs diff --git a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/docStatus.ts b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/docStatus.ts index 9472b88b..4efae42b 100644 --- a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/docStatus.ts +++ b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/docStatus.ts @@ -2,9 +2,11 @@ import { inArray } from "drizzle-orm"; import { db } from "@/app/db/db"; import { uploadedFiles } from "@/app/db/schema/uploaded_files"; import { getRequiredDocs } from "@/app/lib/measureDocumentRequirements"; +import { isInstallDocType } from "./propertyDocuments"; import { EXPECTED_RETROFIT_ASSESSMENT_DOC_TYPES, SURVEY_ALL_DOC_TYPES, + DESIGN_DOC_TYPES, } from "./types"; import type { HubspotDeal, @@ -81,6 +83,24 @@ export async function fetchDocsByDealId( return docsByDealId; } +/** + * The single source of truth for "which deals have a Retrofit Design Document". + * Derived from the already-fetched per-deal documents (which include both the + * direct deal-id match and the UPRN fallback), so no extra query is needed. + * `DESIGN_DOC_TYPES` defines what counts as a design document. + */ +export function deriveDesignDocDealIds( + docsByDealId: Map, +): Set { + const designDocDealIds = new Set(); + for (const [dealId, docs] of docsByDealId) { + if (docs.some((d) => DESIGN_DOC_TYPES.has(d.fileType))) { + designDocDealIds.add(dealId); + } + } + return designDocDealIds; +} + export function computeDocStatusMap( deals: HubspotDeal[], docsByDealId: Map>, @@ -103,7 +123,12 @@ export function computeDocStatusMap( for (const [dealId, docs] of docsByDealId) { const surveyDocs = docs.filter((d) => SURVEY_ALL_DOC_TYPES.has(d.fileType)); - const installDocs = docs.filter((d) => !SURVEY_ALL_DOC_TYPES.has(d.fileType)); + // Survey, coordination and design docs each get their own drawer section, + // so none count as install docs. `isInstallDocType` is the shared predicate + // that keeps this in sync with the drawer's own split — re-implementing it + // inline once dropped the coordination carve-out and mis-bucketed + // coordination-only docs as install documents. + const installDocs = docs.filter((d) => isInstallDocType(d.fileType)); const surveyTypeSet = new Set(surveyDocs.map((d) => d.fileType)); const measures = measuresByDealId.get(dealId) ?? []; diff --git a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/page.tsx b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/page.tsx index 6b50ee96..a83564df 100644 --- a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/page.tsx +++ b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/page.tsx @@ -4,7 +4,11 @@ import { redirect } from "next/navigation"; import { eq, inArray, and, desc, sql } from "drizzle-orm"; import LiveTracker from "./LiveTracker"; import { computeLiveTrackerData } from "./transforms"; -import { fetchDocsByDealId, computeDocStatusMap } from "./docStatus"; +import { + fetchDocsByDealId, + computeDocStatusMap, + deriveDesignDocDealIds, +} from "./docStatus"; import { db } from "@/app/db/db"; import { hubspotDealData } from "@/app/db/schema/crm/hubspot_deal_table"; import { portfolioOrganisation } from "@/app/db/schema/portfolio_organisation"; @@ -112,7 +116,14 @@ export default async function LiveReportingPage(props: { .where(inArray(hubspotDealData.companyId, companyIds)); const deals = rawDeals.map(mapDbRowToHubspotDeal); - const trackerData = computeLiveTrackerData(deals); + const dealIds = deals.map((d) => d.dealId).filter(Boolean); + + // Fetch per-deal documents before classification so Retrofit Design Document + // presence can drive the Design-vs-Installation boundary. The same fetched + // documents feed the document-status map below. + const docsByDealId = await fetchDocsByDealId(deals, dealIds); + const designDocDealIds = deriveDesignDocDealIds(docsByDealId); + const trackerData = computeLiveTrackerData(deals, designDocDealIds); const userEmail = user?.user?.email; @@ -165,7 +176,6 @@ export default async function LiveReportingPage(props: { // Fetch currently approved measures for all deals in scope const approvalsByDeal: ApprovalsByDeal = {}; - const dealIds = deals.map((d) => d.dealId).filter(Boolean); if (dealIds.length > 0) { const approvalRows = await db .select({ @@ -218,7 +228,6 @@ export default async function LiveReportingPage(props: { const removalStatusByDeal: RemovalStatusByDeal = computeRemovalStatusByDeal(removalRows); - const docsByDealId = await fetchDocsByDealId(deals, dealIds); const docStatusMap = computeDocStatusMap(deals, docsByDealId, approvalsByDeal); return ( diff --git a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/propertyDocuments.ts b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/propertyDocuments.ts index e9ebf415..9bab6454 100644 --- a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/propertyDocuments.ts +++ b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/propertyDocuments.ts @@ -6,6 +6,19 @@ import { } from "./types"; import type { PropertyDocument, MeasureDocProgress } from "./types"; +// Survey, coordination and design docs each get their own section in the +// property drawer, so none of them count as install docs. Kept as a single +// predicate shared with computeDocStatusMap: when the two drifted apart, the +// Install Docs badge in the properties table read "Has Docs" for properties +// whose drawer showed no install documents at all. +export function isInstallDocType(docType: string): boolean { + return ( + !SURVEY_ALL_DOC_TYPES.has(docType) && + !COORDINATION_DOC_TYPES.has(docType) && + !DESIGN_DOC_TYPES.has(docType) + ); +} + export function splitDocumentsByType(docs: PropertyDocument[]): { docs: PropertyDocument[]; coordinationDocs: PropertyDocument[]; @@ -16,12 +29,7 @@ export function splitDocumentsByType(docs: PropertyDocument[]): { docs: docs.filter((d) => SURVEY_ALL_DOC_TYPES.has(d.docType)), coordinationDocs: docs.filter((d) => COORDINATION_DOC_TYPES.has(d.docType)), designDocs: docs.filter((d) => DESIGN_DOC_TYPES.has(d.docType)), - installDocs: docs.filter( - (d) => - !SURVEY_ALL_DOC_TYPES.has(d.docType) && - !COORDINATION_DOC_TYPES.has(d.docType) && - !DESIGN_DOC_TYPES.has(d.docType), - ), + installDocs: docs.filter((d) => isInstallDocType(d.docType)), }; } diff --git a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/transforms.test.ts b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/transforms.test.ts index 60b68e4e..cec5ed4e 100644 --- a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/transforms.test.ts +++ b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/transforms.test.ts @@ -300,81 +300,123 @@ describe("resolveDisplayStage — AFTER_ASSESSMENT sub-classification", () => { ).toBe("Design in Progress"); }); - it("is case-insensitive for coord/design status checks", () => { + it("is case-insensitive for the coordination-complete pattern", () => { expect( - resolveDisplayStage(makeDeal({ - dealstage: AFTER_ASSESSMENT_STAGE, - coordinationStatus: "(v1) ioe/mtp complete", - designStatus: "uploaded", - })) - ).toBe("Installation in Progress"); // POST_DESIGN, no install fields set + resolveDisplayStage( + makeDeal({ + dealstage: AFTER_ASSESSMENT_STAGE, + coordinationStatus: "(v1) ioe/mtp complete", + }), + true // Retrofit Design Document present + ) + ).toBe("Installation in Progress"); }); }); -describe("resolveDisplayStage — POST_DESIGN sub-classification (design UPLOADED)", () => { +describe("resolveDisplayStage — after-coordination precedence (downstream evidence wins over document presence)", () => { const AFTER_ASSESSMENT_STAGE = "3948185842"; - function makePostDesignDeal(overrides: Partial = {}): HubspotDeal { + // A coordination-complete deal. designStatus is deliberately unset — it no + // longer influences classification; the Retrofit Design Document (passed via + // hasDesignDoc) is the source of truth for the Design/Installation boundary. + function makeCoordinationCompleteDeal(overrides: Partial = {}): HubspotDeal { return makeDeal({ dealstage: AFTER_ASSESSMENT_STAGE, coordinationStatus: "(V1) IOE/MTP COMPLETE", - designStatus: "UPLOADED", ...overrides, }); } - it("returns Installation in Progress when no install fields are set", () => { - expect(resolveDisplayStage(makePostDesignDeal())).toBe("Installation in Progress"); + it("returns Design in Progress when the design document is absent and there is no downstream evidence", () => { + expect(resolveDisplayStage(makeCoordinationCompleteDeal(), false)).toBe("Design in Progress"); }); - it("returns Installation Complete when actualMeasuresInstalled is set", () => { + it("returns Installation Complete when actualMeasuresInstalled is set even though the design document is absent", () => { expect( - resolveDisplayStage(makePostDesignDeal({ actualMeasuresInstalled: "Insulation" })) + resolveDisplayStage(makeCoordinationCompleteDeal({ actualMeasuresInstalled: "Insulation" }), false) ).toBe("Installation Complete"); }); - it("returns Installation Complete when installerHandover is set", () => { + it("returns Installation Complete when installerHandover is set even though the design document is absent", () => { expect( - resolveDisplayStage(makePostDesignDeal({ installerHandover: "2024-01-01" })) + resolveDisplayStage(makeCoordinationCompleteDeal({ installerHandover: "2024-01-01" }), false) ).toBe("Installation Complete"); }); - it("returns At Lodgement when lodgementStatus is set", () => { + it("returns At Lodgement when lodgementStatus is set even though the design document is absent", () => { expect( - resolveDisplayStage(makePostDesignDeal({ lodgementStatus: "Submitted" })) + resolveDisplayStage(makeCoordinationCompleteDeal({ lodgementStatus: "Submitted" }), false) ).toBe("At Lodgement"); }); - it("returns At Post Survey when measuresLodgementDate is set", () => { + it("returns At Post Survey when measuresLodgementDate is set even though the design document is absent", () => { expect( - resolveDisplayStage(makePostDesignDeal({ measuresLodgementDate: new Date() })) + resolveDisplayStage(makeCoordinationCompleteDeal({ measuresLodgementDate: new Date() }), false) ).toBe("At Post Survey"); }); - it("returns Project Complete when fullLodgementDate is set", () => { + it("returns Project Complete when fullLodgementDate is set even though the design document is absent", () => { expect( - resolveDisplayStage(makePostDesignDeal({ fullLodgementDate: new Date() })) + resolveDisplayStage(makeCoordinationCompleteDeal({ fullLodgementDate: new Date() }), false) ).toBe("Project Complete"); }); it("fullLodgementDate takes precedence over measuresLodgementDate and lodgementStatus", () => { expect( - resolveDisplayStage(makePostDesignDeal({ - fullLodgementDate: new Date(), - measuresLodgementDate: new Date(), - lodgementStatus: "Submitted", - })) + resolveDisplayStage( + makeCoordinationCompleteDeal({ + fullLodgementDate: new Date(), + measuresLodgementDate: new Date(), + lodgementStatus: "Submitted", + }), + false + ) ).toBe("Project Complete"); }); it("measuresLodgementDate takes precedence over lodgementStatus", () => { expect( - resolveDisplayStage(makePostDesignDeal({ - measuresLodgementDate: new Date(), - lodgementStatus: "Submitted", - })) + resolveDisplayStage( + makeCoordinationCompleteDeal({ + measuresLodgementDate: new Date(), + lodgementStatus: "Submitted", + }), + false + ) ).toBe("At Post Survey"); }); + + it("does NOT return Installation in Progress for designStatus UPLOADED when the design document is absent (regression for the reported bug)", () => { + // The HubSpot designStatus flag can be set before — or without — the + // Retrofit Design Document ever being uploaded. It must no longer push a + // Property into Installation in Progress. + expect( + resolveDisplayStage(makeCoordinationCompleteDeal({ designStatus: "UPLOADED" }), false) + ).toBe("Design in Progress"); + }); +}); + +describe("resolveDisplayStage — design-document presence drives the Design/Installation boundary", () => { + const AFTER_ASSESSMENT_STAGE = "3948185842"; + + function makeCoordinationCompleteDeal(overrides: Partial = {}): HubspotDeal { + return makeDeal({ + dealstage: AFTER_ASSESSMENT_STAGE, + coordinationStatus: "(V1) IOE/MTP COMPLETE", + ...overrides, + }); + } + + it("returns Installation in Progress when the Retrofit Design Document is present and there is no downstream evidence", () => { + // Arrange + const deal = makeCoordinationCompleteDeal(); + + // Act + const stage = resolveDisplayStage(deal, true); + + // Assert + expect(stage).toBe("Installation in Progress"); + }); }); // ----------------------------------------------------------------------- @@ -402,6 +444,19 @@ describe("classifyDeals", () => { expect(result.dealId).toBe("abc-123"); expect(result.dealname).toBe("Test"); }); + + it("classifies a coordination-complete deal as Installation in Progress only when its id is in the design-document set", () => { + // Arrange + const withDoc = makeDeal({ dealId: "has-doc", coordinationStatus: "(V1) IOE/MTP COMPLETE" }); + const withoutDoc = makeDeal({ dealId: "no-doc", coordinationStatus: "(V1) IOE/MTP COMPLETE" }); + + // Act + const [a, b] = classifyDeals([withDoc, withoutDoc], new Set(["has-doc"])); + + // Assert + expect(a.displayStage).toBe("Installation in Progress"); + expect(b.displayStage).toBe("Design in Progress"); + }); }); // ----------------------------------------------------------------------- @@ -668,6 +723,25 @@ describe("computeLiveTrackerData", () => { expect(result.projects).toHaveLength(0); expect(result.totalDeals).toBe(0); }); + + it("reflects design-document presence in the project roll-up stage counts", () => { + // Arrange — two coordination-complete deals in one project, one with a + // Retrofit Design Document and one without. + const deals = [ + makeDeal({ projectCode: "PROJ-A", dealId: "has-doc", coordinationStatus: "(V1) IOE/MTP COMPLETE" }), + makeDeal({ projectCode: "PROJ-A", dealId: "no-doc", coordinationStatus: "(V1) IOE/MTP COMPLETE" }), + ]; + + // Act + const result = computeLiveTrackerData(deals, new Set(["has-doc"])); + + // Assert + const stageProgress = result.projects[0].progress.stageProgress; + const design = stageProgress.find((s) => s.stage === "Design in Progress")!; + const install = stageProgress.find((s) => s.stage === "Installation in Progress")!; + expect(design.count).toBe(1); + expect(install.count).toBe(1); + }); }); describe("hasMajorConditionIssue", () => { diff --git a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/transforms.ts b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/transforms.ts index 8804a506..cf840911 100644 --- a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/transforms.ts +++ b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/transforms.ts @@ -70,14 +70,16 @@ const STAGE_ID_MAP: Record = { // ----------------------------------------------------------------------- // After-assessment sub-classification -// Resolves AFTER_ASSESSMENT deals based on coordinationStatus + designStatus +// Resolves AFTER_ASSESSMENT deals based on coordinationStatus alone. +// Whether coordination is complete is a CRM signal; what happens *after* +// coordination (design vs installation and beyond) is resolved separately +// by resolveAfterCoordinationStage, using document presence + downstream +// evidence rather than the self-reported designStatus flag. // ----------------------------------------------------------------------- function resolveAfterAssessmentStage( - coordinationStatus: string | null, - designStatus: string | null -): "Coordination in Progress" | "Design in Progress" | "POST_DESIGN" | "Queries" { + coordinationStatus: string | null +): "Coordination in Progress" | "AFTER_COORDINATION" | "Queries" { const coord = coordinationStatus?.toUpperCase() ?? ""; - const design = designStatus?.toUpperCase() ?? ""; // RA ISSUE always -> Queries if (coord === "RA ISSUE") return "Queries"; @@ -88,7 +90,7 @@ function resolveAfterAssessmentStage( coord.includes("(V2) IOE/MTP COMPLETE") || coord.includes("(V3) IOE/MTP COMPLETE") ) { - return design === "UPLOADED" ? "POST_DESIGN" : "Design in Progress"; + return "AFTER_COORDINATION"; } // Default for AFTER_ASSESSMENT @@ -96,22 +98,34 @@ function resolveAfterAssessmentStage( } // ----------------------------------------------------------------------- -// Post-design sub-classification -// Called when design is UPLOADED — resolves install / lodgement / completed +// After-coordination sub-classification +// Resolves a coordination-complete deal to design / installation / lodgement +// / completed. Downstream evidence (measures installed, installer handover, +// lodgement, completion) always wins; document presence only decides the +// Design-vs-Installation boundary. Gating the whole block on document +// presence would drag a genuinely installed/lodged Property back to Design +// in Progress when its design document is missing from the store — see +// ADR-0023. // ----------------------------------------------------------------------- -function resolvePostDesignStage(deal: HubspotDeal): DisplayStage { +function resolveAfterCoordinationStage( + deal: HubspotDeal, + hasDesignDoc: boolean +): DisplayStage { if (deal.fullLodgementDate) return "Project Complete"; if (deal.measuresLodgementDate) return "At Post Survey"; if (deal.lodgementStatus) return "At Lodgement"; if (deal.actualMeasuresInstalled || deal.installerHandover) return "Installation Complete"; - return "Installation in Progress"; + if (hasDesignDoc) return "Installation in Progress"; + return "Design in Progress"; } // ----------------------------------------------------------------------- // Resolve display stage for a single deal -// Maps dealstage ID + coordination/design/install status -> DisplayStage +// Maps dealstage ID + coordination/install status + Retrofit Design Document +// presence -> DisplayStage. Design-document presence is passed in explicitly +// (hasDesignDoc) so this function stays pure — it never reads the doc store. // ----------------------------------------------------------------------- -export function resolveDisplayStage(deal: HubspotDeal): DisplayStage { +export function resolveDisplayStage(deal: HubspotDeal, hasDesignDoc = false): DisplayStage { if (deal.batch === "Removed from Program") { return "Removed from Program"; } @@ -126,13 +140,10 @@ export function resolveDisplayStage(deal: HubspotDeal): DisplayStage { const raw = STAGE_ID_MAP[deal.dealstage ?? ""] ?? "AFTER_ASSESSMENT"; if (raw === "AFTER_ASSESSMENT") { - const afterAssessment = resolveAfterAssessmentStage( - deal.coordinationStatus, - deal.designStatus - ); + const afterAssessment = resolveAfterAssessmentStage(deal.coordinationStatus); - if (afterAssessment === "POST_DESIGN") { - return resolvePostDesignStage(deal); + if (afterAssessment === "AFTER_COORDINATION") { + return resolveAfterCoordinationStage(deal, hasDesignDoc); } return afterAssessment; @@ -152,10 +163,13 @@ export function resolveDisplayStage(deal: HubspotDeal): DisplayStage { // Classify all deals in a list // Adds displayStage to each deal // ----------------------------------------------------------------------- -export function classifyDeals(deals: HubspotDeal[]): ClassifiedDeal[] { +export function classifyDeals( + deals: HubspotDeal[], + designDocDealIds: ReadonlySet = new Set() +): ClassifiedDeal[] { return deals.map((deal) => ({ ...deal, - displayStage: resolveDisplayStage(deal), + displayStage: resolveDisplayStage(deal, designDocDealIds.has(deal.dealId)), })); } @@ -280,10 +294,11 @@ export function hasMajorConditionIssue(deal: { // Orchestrates all transformations: classify, group by project, compute stats // ----------------------------------------------------------------------- export function computeLiveTrackerData( - rawDeals: HubspotDeal[] + rawDeals: HubspotDeal[], + designDocDealIds: ReadonlySet = new Set() ): Omit { // Classify all deals (add displayStage field) - const classified = classifyDeals(rawDeals); + const classified = classifyDeals(rawDeals, designDocDealIds); // Group deals by projectCode const grouped: Record = {}; diff --git a/src/app/projects/[projectId]/components/DashboardBands.tsx b/src/app/projects/[projectId]/components/DashboardBands.tsx new file mode 100644 index 00000000..46695545 --- /dev/null +++ b/src/app/projects/[projectId]/components/DashboardBands.tsx @@ -0,0 +1,298 @@ +/** + * Presentational pieces of the programme dashboard (issue #418). + * + * All Server Components — the dashboard is a read of already-aggregated + * numbers, so nothing here needs client state, an effect or a query hook. + * These components hold no rules: every number arrives already derived by + * `@/lib/projects/dashboardSummary`, which applies `@/lib/projects/derivations`. + * + * Layout follows the wireframe's three bands (KPI, needs-attention, tables). + * "Awaiting auth", "No access" and notifications are cut, as the issue + * specifies — the schema does not carry them. + */ +import Link from "next/link"; +import type { + ContractorSummaryRow, + DashboardKpi, + NeedsAttention, + WorkstreamSummaryRow, +} from "@/lib/projects/dashboardSummary"; +import { formatRatio } from "@/lib/projects/dashboardSummary"; +import type { RecentWorkOrder } from "@/app/repositories/projects/dashboardRepository"; + +const count = (n: number) => n.toLocaleString("en-GB"); + +/** Band 1 — the headline programme numbers. */ +export function KpiBand({ kpi }: { kpi: DashboardKpi }) { + const tiles = [ + { label: "Total work orders", value: count(kpi.totalOrders) }, + { label: "In progress", value: count(kpi.inProgress) }, + { label: "Completed", value: count(kpi.complete) }, + { label: "Overdue", value: count(kpi.overdue), tone: kpi.overdue > 0 }, + { + label: "Required evidence", + value: formatRatio(kpi.evidence.ratio), + hint: + kpi.evidence.ratio === null + ? "No requirements configured" + : `${count(kpi.evidence.satisfied)} of ${count(kpi.evidence.required)}`, + }, + ]; + + return ( +
+ Programme health +
+ {tiles.map((tile) => ( +
+

{tile.label}

+

+ {tile.value} +

+ {tile.hint ? ( +

{tile.hint}

+ ) : null} +
+ ))} +
+
+ ); +} + +/** Band 2 — what someone should go and do something about. */ +export function NeedsAttentionBand({ + needsAttention, + workOrdersHref, +}: { + needsAttention: NeedsAttention; + workOrdersHref: string; +}) { + const items = [ + { label: "Overdue", value: needsAttention.overdue }, + { label: "Missing required docs", value: needsAttention.ordersMissingRequiredDocs }, + { label: "No contractor assigned", value: needsAttention.unassignedContractor }, + ]; + + return ( +
+ Needs attention +
+ {items.map((item) => ( + 0 + ? "border-amber-200 bg-amber-50 hover:bg-amber-100" + : "border-gray-200 bg-white hover:bg-gray-50" + }`} + > +

{item.label}

+

+ {count(item.value)} +

+ + ))} +
+
+ ); +} + +/** Band 3a — orders, completion, overdue and missing docs per workstream. */ +export function WorkstreamsTable({ rows }: { rows: WorkstreamSummaryRow[] }) { + return ( +
+ Workstreams + + {rows.map((row) => ( + + {row.name} + {count(row.orders)} + {formatRatio(row.completeRatio)} + 0}>{count(row.overdue)} + 0}> + {count(row.ordersMissingRequiredDocs)} + + + ))} + +
+ ); +} + +/** Band 3b — the same view sliced by contractor organisation. */ +export function ContractorsTable({ rows }: { rows: ContractorSummaryRow[] }) { + return ( +
+ Contractors + + {rows.map((row) => ( + + + {row.name} + + {count(row.orders)} + 0}>{count(row.overdue)} + {formatRatio(row.evidence.ratio)} + + ))} + +
+ ); +} + +/** Band 3c — the most recently touched work orders, linking to the full table. */ +export function RecentWorkOrders({ + rows, + workOrdersHref, +}: { + rows: RecentWorkOrder[]; + workOrdersHref: string; +}) { + return ( +
+
+ Recent work orders + + View all + +
+ + {rows.map((row) => ( + + {row.reference} + + {row.propertyAddress ?? "—"} + {row.propertyPostcode ? ( + · {row.propertyPostcode} + ) : null} + + {row.workstreamName} + {row.stageName} + {row.forecastEnd ?? "—"} + + ))} + +
+ ); +} + +function BandHeading({ children }: { children: React.ReactNode }) { + return ( +

+ {children} +

+ ); +} + +/** A column header: `numeric` right-aligns it to match its `Td`s. */ +interface Column { + label: string; + numeric?: boolean; +} + +function TableFrame({ + head, + empty, + children, +}: { + head: Column[]; + empty: string | null; + children: React.ReactNode; +}) { + if (empty) { + return ( +
+ {empty} +
+ ); + } + return ( +
+ + + + {head.map((column) => ( + + ))} + + + {children} +
+ {column.label} +
+
+ ); +} + +function Td({ + children, + numeric, + tone, + className = "", +}: { + children: React.ReactNode; + numeric?: boolean; + tone?: boolean; + className?: string; +}) { + return ( + + {children} + + ); +} diff --git a/src/app/projects/[projectId]/import/components/ColumnMappingTable.tsx b/src/app/projects/[projectId]/import/components/ColumnMappingTable.tsx new file mode 100644 index 00000000..0a24b358 --- /dev/null +++ b/src/app/projects/[projectId]/import/components/ColumnMappingTable.tsx @@ -0,0 +1,176 @@ +"use client"; + +import { + assignColumn, + columnMappingRows, + IMPORT_FIELDS, + IMPORT_FIELDS_BY_KEY, + IMPORT_REQUIREMENTS, + summariseColumnMapping, + type ImportColumnMapping, + type ImportFieldKey, +} from "@/lib/projects/import/columnMapping"; +import { MappingSelect, MappingStatusIcon } from "./MappingSelect"; + +/** Fields named by a requirement carry the "required" tag in the picker. */ +const REQUIRED_KEYS = new Set( + IMPORT_REQUIREMENTS.flatMap((requirement) => requirement.keys), +); + +/** + * Layer 1 of the mapping step (issue #415): one row per **file column**, each + * pointed at an Ara field, at "don't import", or at nothing yet. + * + * Rows are file columns rather than Ara fields because that is the direction + * the wireframe reads (file → Ara) and the direction the user thinks in — they + * are looking at their own spreadsheet. Which *fields* are still missing is a + * separate question, answered by the blocker list beneath the table, since a + * missing field has no row of its own to complain from. + * + * Stateless: it renders the mapping it is handed and reports edits upward, so + * the whole screen re-derives from one value. + */ +export function ColumnMappingTable({ + headers, + preview, + mapping, + onChange, +}: { + headers: string[]; + /** Sample rows, for the "e.g. …" hint under each heading. */ + preview: string[][]; + mapping: ImportColumnMapping; + onChange: (next: ImportColumnMapping) => void; +}) { + const rows = columnMappingRows(headers, mapping, preview); + const summary = summariseColumnMapping(headers, mapping); + + return ( +
+
+
+

Column mapping

+

+ Match each column in your file to the field it holds. +

+
+ + File → Ara + +
+ +
+ + + + + + + + + + {rows.map((row) => ( + + + + + + ))} + +
File columnStatusAra field
+
{row.header}
+ {row.sample !== "" && ( +
+ e.g. {row.sample} +
+ )} +
+ + + + onChange( + assignColumn( + mapping, + row.columnIndex, + next === "__ignore__" + ? "ignore" + : (next as ImportFieldKey | null), + ), + ) + } + options={[ + ...IMPORT_FIELDS.map((field) => { + const heldBy = mapping.fields[field.key]; + return { + value: field.key, + label: REQUIRED_KEYS.has(field.key) + ? `${field.label} (required)` + : field.label, + // Say so when picking this field would take it off + // another column, rather than silently moving it. + hint: + heldBy !== undefined && heldBy !== row.columnIndex + ? `currently ${headers[heldBy]}` + : field.hint, + }; + }), + { value: "__ignore__", label: "Don't import this column" }, + ]} + /> +
+
+ + {summary.missingRequirements.length > 0 && ( +
+

+ {summary.missingRequirements.length} required field + {summary.missingRequirements.length === 1 ? "" : "s"} still to map +

+
    + {summary.missingRequirements.map((requirement) => ( +
  • + {requirement.label} —{" "} + {requirement.reason} +
  • + ))} +
+
+ )} + + {summary.complete && summary.unmappedOptionalFields.length > 0 && ( +
+

+ Not mapped (optional):{" "} + {summary.unmappedOptionalFields + .map((key) => IMPORT_FIELDS_BY_KEY[key].label) + .join(", ")} + . +

+
+ )} +
+ ); +} diff --git a/src/app/projects/[projectId]/import/components/ImportMapping.tsx b/src/app/projects/[projectId]/import/components/ImportMapping.tsx new file mode 100644 index 00000000..f0fbeb17 --- /dev/null +++ b/src/app/projects/[projectId]/import/components/ImportMapping.tsx @@ -0,0 +1,242 @@ +"use client"; + +import { useState } from "react"; +import { + ArrowLeftIcon, + DocumentTextIcon, + ExclamationTriangleIcon, +} from "@heroicons/react/24/outline"; +import { Button } from "@/app/shadcn_components/ui/button"; +import { + autoMatchColumns, + summariseColumnMapping, +} from "@/lib/projects/import/columnMapping"; +import type { ImportMappingTargets } from "@/lib/projects/import/mappingTargets"; +import { + buildImportSession, + sessionMatchesFile, + type ImportSession, +} from "@/lib/projects/import/session"; +import { + buildValueMappingModel, + EMPTY_VALUE_MAPPING, +} from "@/lib/projects/import/valueMapping"; +import { ColumnMappingTable } from "./ColumnMappingTable"; +import { ValueMappingTables } from "./ValueMappingTables"; +import type { ParsedImportResponse } from "./ImportUpload"; + +/** What the mapping step hands to validation (#417) when the user continues. */ +export interface MappingHandoff { + session: ImportSession; + /** Rows that will fail validation as mapped — a warning, never a blocker. */ + warningRows: number; +} + +/** + * Work-order import, step 2 of 3 — column mapping and value mapping (#415). + * + * Wireframes: `08-map-columns-rebuilt.html` (value mapping locked) and + * `09-map-columns-workstream-unlocked.html` (unlocked). + * + * Holds the two mapping layers and nothing else. Every figure on the screen — + * statuses, counts, which values need review, whether Continue is enabled — is + * **derived inline** from `(file, columnMapping, valueMapping, targets)` on each + * render rather than stored, so the tables cannot disagree with the mapping the + * user is looking at. That is also why re-pointing the workstream column + * immediately re-groups the contractor and stage tables: they were never a + * separate copy of the answer. + * + * The initial column mapping is auto-matched once, in the `useState` + * initialiser — unless a session for this same file comes back in, which is + * what returning from a later step restores. It is a *suggestion*, so it + * belongs in state (the user edits it) rather than being recomputed each render. + * + * Every edit also reports the whole session upward. That is what "persist the + * mapping alongside the import session" amounts to while the session is + * client-held (ADR-0020): the parent owns the session, this component owns the + * editing of it, and stepping away and back does not lose the work. + */ +export function ImportMapping({ + file, + targets, + initialSession, + onSessionChange, + onBack, + onContinue, +}: { + file: ParsedImportResponse; + targets: ImportMappingTargets; + /** A previously-edited session to resume; ignored unless it fits this file. */ + initialSession?: ImportSession | null; + /** Called with the full session after every edit, so the parent can keep it. */ + onSessionChange?: (session: ImportSession) => void; + onBack: () => void; + onContinue: (handoff: MappingHandoff) => void; +}) { + // A mapping is a set of column indices, so a session from a *different* file + // would map the wrong columns; `sessionMatchesFile` is what refuses it. + const resumed = + initialSession && sessionMatchesFile(initialSession, file) + ? initialSession + : null; + + const [columnMapping, setColumnMapping] = useState( + () => resumed?.columnMapping ?? autoMatchColumns(file.headers), + ); + const [valueMapping, setValueMapping] = useState( + () => resumed?.valueMapping ?? EMPTY_VALUE_MAPPING, + ); + + function updateColumns(next: typeof columnMapping) { + setColumnMapping(next); + onSessionChange?.(buildImportSession(file, next, valueMapping)); + } + + function updateValues(next: typeof valueMapping) { + setValueMapping(next); + onSessionChange?.(buildImportSession(file, columnMapping, next)); + } + + const summary = summariseColumnMapping(file.headers, columnMapping); + const valueModel = buildValueMappingModel( + file.rows, + columnMapping, + valueMapping, + targets, + ); + + const valuesNeedingReview = + valueModel.needsReview.workstreams + + valueModel.needsReview.contractors + + valueModel.needsReview.stages; + + return ( +
+
+
+ +
+

+ {file.filename} +

+

+ {file.rowCount.toLocaleString("en-GB")} row + {file.rowCount === 1 ? "" : "s"} · {file.headers.length} column + {file.headers.length === 1 ? "" : "s"} +

+
+
+
+
+
0 ? "warning" : "plain" + } + /> +
+
+ +
+ +
+ + + + {summary.complete && valueModel.warningRows > 0 && ( +
+ +
+

+ {valueModel.warningRows.toLocaleString("en-GB")} of{" "} + {file.rowCount.toLocaleString("en-GB")} rows will fail validation + as mapped +

+

+ Rows with an unmapped workstream, a missing or unmapped contractor, + or a stage that matches nothing cannot be imported. You can + continue and deal with them at validation, or map the values above + first. +

+
+
+ )} + +
+ + +
+ {!summary.complete && ( +

+ Map{" "} + {summary.missingRequirements.map((r) => r.label).join(", ")} to + continue. +

+ )} + +
+
+
+ ); +} + +/** One figure in the file summary card. */ +function Figure({ + label, + value, + tone = "plain", +}: { + label: string; + value: number; + tone?: "plain" | "warning"; +}) { + return ( +
+

+ {label} +

+

+ {value.toLocaleString("en-GB")} +

+
+ ); +} diff --git a/src/app/projects/[projectId]/import/components/ImportSetupIncomplete.tsx b/src/app/projects/[projectId]/import/components/ImportSetupIncomplete.tsx new file mode 100644 index 00000000..b175c323 --- /dev/null +++ b/src/app/projects/[projectId]/import/components/ImportSetupIncomplete.tsx @@ -0,0 +1,76 @@ +import Link from "next/link"; +import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; +import type { ImportReadiness } from "@/lib/projects/import/readiness"; + +/** Human-readable phrase for each unmet requirement. */ +const GAP_LABEL = { + stages: "no stages", + contractor: "no contractor assigned", +} as const; + +/** + * Shown in place of the drop zone when the project is not yet set up enough to + * import against (ADR-0019). A plain server component — it renders the + * `ImportReadiness` the page already loaded, so no client state is involved. + * + * It deliberately explains *which* workstreams are incomplete and *why*, rather + * than a bare "not ready", so the user knows exactly what to fix before + * returning. `setupHref` points at the project's configuration; the concrete + * per-step wizard routes (select workstreams / configure stages / assign + * contractors) land in other issues, so the page passes a single sensible + * destination rather than deep-linking each gap. + */ +export function ImportSetupIncomplete({ + readiness, + setupHref, +}: { + readiness: ImportReadiness; + setupHref: string; +}) { + return ( +
+
+ +
+

+ Finish project setup first +

+

+ {readiness.hasWorkstreams + ? "Every workstream needs at least one stage and an assigned contractor before you can import work orders against it." + : "This project has no workstreams yet. Add the workstreams it covers, give each a stage ladder and a contractor, then come back to import."} +

+ + {readiness.incompleteWorkstreams.length > 0 && ( +
    + {readiness.incompleteWorkstreams.map((w) => ( +
  • + + {w.workstreamName} + + + {w.missing.map((gap) => GAP_LABEL[gap]).join(" · ")} + +
  • + ))} +
+ )} + + + Go to project setup + +
+
+
+ ); +} diff --git a/src/app/projects/[projectId]/import/components/ImportUpload.tsx b/src/app/projects/[projectId]/import/components/ImportUpload.tsx new file mode 100644 index 00000000..532e0867 --- /dev/null +++ b/src/app/projects/[projectId]/import/components/ImportUpload.tsx @@ -0,0 +1,380 @@ +"use client"; + +import { DragEvent, useRef, useState } from "react"; +import { useMutation } from "@tanstack/react-query"; +import { + ArrowDownTrayIcon, + ArrowPathIcon, + CheckCircleIcon, + CloudArrowUpIcon, + DocumentTextIcon, + ExclamationTriangleIcon, +} from "@heroicons/react/24/outline"; +import { Button } from "@/app/shadcn_components/ui/button"; +import { + ACCEPTED_IMPORT_EXTENSIONS, + hasAcceptedImportExtension, + MAX_IMPORT_FILE_BYTES, +} from "@/lib/projects/import/parse"; +import type { ImportMappingTargets } from "@/lib/projects/import/mappingTargets"; +import type { ImportSession } from "@/lib/projects/import/session"; +import { ImportMapping, type MappingHandoff } from "./ImportMapping"; + +/** The parse route's response — the whole file, not just the preview. */ +export interface ParsedImportResponse { + filename: string; + headers: string[]; + rows: string[][]; + rowCount: number; + preview: string[][]; +} + +const MAX_MB = MAX_IMPORT_FILE_BYTES / (1024 * 1024); + +/** Which of the wizard's steps this component is showing. */ +type ImportStep = "upload" | "mapping" | "mapped"; + +/** + * Work-order import drop zone (issue #414) and the step-2 mapping screen it + * hands off to (issue #415). + * + * Uploads the file to the parse route and renders the returned headers and + * preview. The full `rows` array stays here in `parse.data` — the mapping + * (#415), validation (#416) and commit (#417) steps read it from this + * component's state rather than re-fetching or re-parsing, which is why the + * route hands back every row and not only the preview. + * + * The step is client state rather than a route because the parsed file lives + * here: navigating to a `/import/mapping` URL would drop the rows on the floor + * and force a re-upload on every Back. Going back to the upload step therefore + * keeps the parsed file, and only choosing a different file discards it. + */ +export function ImportUpload({ + projectId, + targets, +}: { + projectId: string; + /** The project's workstreams, stages and contractors — the value-mapping targets. */ + targets: ImportMappingTargets; +}) { + const fileInputRef = useRef(null); + const [isDragging, setIsDragging] = useState(false); + const [fileName, setFileName] = useState(null); + // Size/extension failures caught before the upload; the route re-checks both. + const [clientError, setClientError] = useState(null); + const [step, setStep] = useState("upload"); + // The import session: the file's mapping, held here so stepping back to the + // drop zone and forward again does not throw the user's work away. Nothing is + // written server-side until commit (#417) — see ADR-0020. + const [session, setSession] = useState(null); + // Set when the user finishes mapping — the artefact validation (#417) takes. + const [handoff, setHandoff] = useState(null); + + const parse = useMutation({ + mutationFn: async (file: File) => { + const form = new FormData(); + form.append("file", file); + const res = await fetch(`/api/projects/${projectId}/import/parse`, { + method: "POST", + body: form, + }); + const body = await res.json(); + if (!res.ok) throw new Error(body.error ?? "Couldn't read that file"); + return body; + }, + }); + + function onFile(file: File) { + setClientError(null); + parse.reset(); + setFileName(file.name); + // A different file means a different set of columns, so any mapping made + // against the old one is meaningless (see `sessionMatchesFile`). + setStep("upload"); + setSession(null); + setHandoff(null); + + if (!hasAcceptedImportExtension(file.name)) { + setClientError( + `That file type isn't supported — upload a ${ACCEPTED_IMPORT_EXTENSIONS.join(", ")} file.`, + ); + return; + } + if (file.size > MAX_IMPORT_FILE_BYTES) { + setClientError( + `That file is larger than ${MAX_MB}MB — split it into smaller files.`, + ); + return; + } + parse.mutate(file); + } + + function handleDragOver(e: DragEvent) { + e.preventDefault(); + setIsDragging(true); + } + + function handleDrop(e: DragEvent) { + e.preventDefault(); + setIsDragging(false); + const dropped = e.dataTransfer.files?.[0]; + if (dropped) onFile(dropped); + } + + function reset() { + setFileName(null); + setClientError(null); + parse.reset(); + setStep("upload"); + setSession(null); + setHandoff(null); + if (fileInputRef.current) fileInputRef.current.value = ""; + } + + const error = clientError ?? (parse.isError ? parse.error.message : null); + const parsed = parse.data; + + if (parsed && step === "mapping") { + return ( + setStep("upload")} + onContinue={(next) => { + setHandoff(next); + setStep("mapped"); + }} + /> + ); + } + + if (parsed && step === "mapped" && handoff) { + return ( + setStep("mapping")} + onStartOver={reset} + /> + ); + } + + return ( +
+ + + + + {error && ( +
+ +
+

Couldn't import that file

+

{error}

+ +
+
+ )} + + {parsed && ( +
+
+
+ +
+

+ {parsed.filename} +

+

+ {parsed.rowCount.toLocaleString("en-GB")} row + {parsed.rowCount === 1 ? "" : "s"} ·{" "} + {parsed.headers.length} column + {parsed.headers.length === 1 ? "" : "s"} +

+
+
+ +
+ +
+ + + + {parsed.headers.map((header, i) => ( + + ))} + + + + {parsed.preview.map((row, rowIndex) => ( + + {row.map((cell, cellIndex) => ( + + ))} + + ))} + +
+ {header} +
+ {cell === "" ? ( + + ) : ( + cell + )} +
+
+ + {parsed.rowCount > parsed.preview.length && ( +

+ Showing the first {parsed.preview.length} of{" "} + {parsed.rowCount.toLocaleString("en-GB")} rows. +

+ )} + +
+ +
+
+ )} +
+ ); +} + +/** + * The end of step 2: the mapping is settled and held in the import session, + * waiting for validation and commit (#417) to consume it. + * + * It states what was captured rather than claiming anything was saved to the + * server, because nothing was — an import writes nothing until commit + * (ADR-0020). Both ways back are offered: edit the mapping, or start again with + * a different file. + */ +function MappingSaved({ + handoff, + onEdit, + onStartOver, +}: { + handoff: MappingHandoff; + onEdit: () => void; + onStartOver: () => void; +}) { + const { session, warningRows } = handoff; + const mappedFields = Object.keys(session.columnMapping.fields).length; + + return ( +
+
+ +
+

+ Mapping complete +

+

+ {mappedFields} field{mappedFields === 1 ? "" : "s"} mapped across{" "} + {session.rowCount.toLocaleString("en-GB")} row + {session.rowCount === 1 ? "" : "s"} of {session.filename}. Nothing + has been written yet — validation and commit arrive in #417. +

+ + {warningRows > 0 && ( +

+ {warningRows.toLocaleString("en-GB")} row + {warningRows === 1 ? "" : "s"} still carry values that map to + nothing and will fail validation. +

+ )} + +
+ + +
+
+
+
+ ); +} diff --git a/src/app/projects/[projectId]/import/components/MappingSelect.tsx b/src/app/projects/[projectId]/import/components/MappingSelect.tsx new file mode 100644 index 00000000..f72f0668 --- /dev/null +++ b/src/app/projects/[projectId]/import/components/MappingSelect.tsx @@ -0,0 +1,126 @@ +"use client"; + +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/app/shadcn_components/ui/select"; + +/** + * The one picker both mapping layers use (issue #415): "this file thing is that + * Ara thing", with an explicit way to say *neither*. + * + * Radix reserves the empty string as a value, so "not mapped" travels as a + * sentinel and is translated at this boundary — callers only ever see + * `string | null`, which is what the mapping modules store. + */ +const NONE = "__none__"; + +export interface MappingOption { + value: string; + label: string; + /** Muted second line — what a column is currently used for, a contractor's org, … */ + hint?: string; +} + +export function MappingSelect({ + value, + options, + onChange, + noneLabel, + placeholder, + disabled = false, + invalid = false, + testId, + ariaLabel, +}: { + /** The chosen option's value, or null when nothing is mapped. */ + value: string | null; + options: MappingOption[]; + /** Called with null when the user picks the "none" entry. */ + onChange: (value: string | null) => void; + /** What choosing nothing means here — "Don't import", "Leave unmapped", … */ + noneLabel: string; + placeholder: string; + disabled?: boolean; + /** Draws the needs-review treatment the wireframe gives unmapped rows. */ + invalid?: boolean; + testId?: string; + ariaLabel: string; +}) { + return ( + + ); +} + +/** The wireframe's per-row status affordance, shared by both tables. */ +export function MappingStatusIcon({ + status, +}: { + status: "matched" | "needs_review" | "ignored"; +}) { + if (status === "matched") { + return ( + + ✓ + + ); + } + if (status === "ignored") { + return ( + + – + + ); + } + return ( + + ? + + ); +} diff --git a/src/app/projects/[projectId]/import/components/ValueMappingTables.tsx b/src/app/projects/[projectId]/import/components/ValueMappingTables.tsx new file mode 100644 index 00000000..95e499c0 --- /dev/null +++ b/src/app/projects/[projectId]/import/components/ValueMappingTables.tsx @@ -0,0 +1,390 @@ +"use client"; + +import { LockClosedIcon } from "@heroicons/react/24/outline"; +import type { ImportMappingTargets } from "@/lib/projects/import/mappingTargets"; +import { + setContractorValue, + setStageValue, + setWorkstreamValue, + type ImportValueMapping, + type ScopedValueEntry, + type ValueMappingModel, +} from "@/lib/projects/import/valueMapping"; +import { MappingSelect, MappingStatusIcon } from "./MappingSelect"; + +/** + * Layer 2 of the mapping step (issue #415): the file's *values* against the + * project's own workstreams, contractors and stages. + * + * Three tables rather than one, because they answer different questions at + * different scopes — and the two lower ones are scoped **by** the first: + * contractors and stages are offered per workstream, since an assignment + * belongs to a workstream and a ladder belongs to a workstream (ADR-0019). + * That is why they are grouped under workstream headings rather than listed + * flat: the same contractor name under two workstreams is two questions. + * + * Locked until column mapping is complete, exactly as wireframe 08 shows — + * there is nothing to list until we know which column holds the workstream. + */ +export function ValueMappingTables({ + model, + targets, + valueMapping, + onChange, + locked, +}: { + model: ValueMappingModel; + targets: ImportMappingTargets; + valueMapping: ImportValueMapping; + onChange: (next: ImportValueMapping) => void; + locked: boolean; +}) { + const contractorOptions = (entry: ScopedValueEntry) => + (targets.workstreams.find((w) => w.id === entry.workstreamId)?.contractors ?? []) + .map((contractor) => ({ value: contractor.id, label: contractor.name })); + + const stageOptions = (entry: ScopedValueEntry) => + (targets.workstreams.find((w) => w.id === entry.workstreamId)?.stages ?? []).map( + (stage, index) => ({ + value: stage.id, + label: stage.name, + hint: index === 0 ? "first stage" : undefined, + }), + ); + + return ( +
+ {locked && ( +
+
+ +

+ Complete column mapping to map cell values +

+

+ We can only list the values in your file once we know which column + each field comes from. +

+
+
+ )} + +
+ 0 + ? `${rows(model.blankRows.workstream)} have no workstream — those rows will fail validation.` + : null, + ]} + > + {model.workstreams.map((entry) => ( + + + onChange(setWorkstreamValue(valueMapping, entry.key, next)) + } + options={targets.workstreams.map((workstream) => ({ + value: workstream.id, + label: workstream.name, + }))} + /> + + ))} + + + + onChange(setContractorValue(valueMapping, entry.key, next)) + } + locked={locked} + empty={ + model.hasContractorColumn + ? "No contractor values to map yet." + : "Map the contractor column first." + } + notes={[ + model.blankRows.contractor > 0 + ? `${rows(model.blankRows.contractor)} have no contractor — those rows will fail validation.` + : null, + model.unscopedRows > 0 + ? `${rows(model.unscopedRows)} are waiting on their workstream value — map it above and their contractors appear here.` + : null, + ]} + /> + + + onChange(setStageValue(valueMapping, entry.key, next)) + } + locked={locked} + empty={ + model.hasStageColumn + ? "No stage values in the file — every row will start at its workstream's first stage." + : "No stage column mapped — every row will start at its workstream's first stage." + } + notes={[ + model.blankRows.stage > 0 + ? `${rows(model.blankRows.stage)} have no stage — they will start at their workstream's first stage.` + : null, + model.needsReview.stages > 0 + ? "A stage that matches nothing is an error — leave the cell blank instead if the work has not started." + : null, + ]} + /> +
+
+ ); +} + +/** "1 row" / "1,248 rows", en-GB grouped. */ +function rows(count: number): string { + return `${count.toLocaleString("en-GB")} row${count === 1 ? "" : "s"}`; +} + +/** The shared chrome of a value table: header, column headings, notes. */ +function ValuePanel({ + title, + subtitle, + testId, + valueHeader = "File value", + targetHeader, + notes, + empty, + children, +}: { + title: string; + subtitle: string; + testId: string; + valueHeader?: string; + targetHeader: string; + notes: Array; + empty: string; + children: React.ReactNode; +}) { + const hasRows = Array.isArray(children) ? children.length > 0 : Boolean(children); + const shown = notes.filter((note): note is string => note !== null); + + return ( +
+
+

{title}

+

{subtitle}

+
+ + {hasRows ? ( +
+ + + + + + + + + {children} +
{valueHeader}Status{targetHeader}
+
+ ) : ( +

{empty}

+ )} + + {shown.length > 0 && ( +
+ {shown.map((note) => ( +

+ {note} +

+ ))} +
+ )} +
+ ); +} + +/** One value row: the file's text, its row count, its status, its picker. */ +function ValueRow({ + value, + rowCount, + status, + matchedBy, + scope, + children, +}: { + value: string; + rowCount: number; + status: "matched" | "needs_review"; + matchedBy: "user" | "auto" | null; + /** The workstream a contractor/stage value sits under, when it has one. */ + scope?: string; + children: React.ReactNode; +}) { + return ( + + + + {value} + +
+ {rows(rowCount)} + {scope && · {scope}} + {matchedBy === "auto" && ( + · auto-matched + )} +
+ + + + + {children} + + ); +} + +/** + * A contractor or stage table: the same rows, grouped under the workstream they + * are scoped to, so it is never ambiguous *which* "Acme" is being mapped. + */ +function ScopedPanel({ + title, + subtitle, + testId, + targetHeader, + entries, + targets, + optionsFor, + onSelect, + placeholder, + noneTargetsNote, + locked, + notes, + empty, +}: { + title: string; + subtitle: string; + testId: string; + targetHeader: string; + entries: ScopedValueEntry[]; + targets: ImportMappingTargets; + optionsFor: (entry: ScopedValueEntry) => Array<{ + value: string; + label: string; + hint?: string; + }>; + onSelect: (entry: ScopedValueEntry, next: string | null) => void; + placeholder: string; + noneTargetsNote: string; + locked: boolean; + notes: Array; + empty: string; +}) { + // Grouped in the targets' own (alphabetical) order so the grouping does not + // reshuffle as values are mapped; within a group the biggest value leads. + const groups = targets.workstreams + .map((workstream) => ({ + workstream, + entries: entries.filter((entry) => entry.workstreamId === workstream.id), + })) + .filter((group) => group.entries.length > 0); + + return ( + + {groups.flatMap((group) => [ + + + {group.workstream.name} + {group.entries[0].noTargets && ( + + {noneTargetsNote} + + )} + + , + ...group.entries.map((entry) => ( + + onSelect(entry, next)} + options={optionsFor(entry)} + /> + + )), + ])} + + ); +} diff --git a/src/app/projects/[projectId]/import/page.tsx b/src/app/projects/[projectId]/import/page.tsx new file mode 100644 index 00000000..b3368ef0 --- /dev/null +++ b/src/app/projects/[projectId]/import/page.tsx @@ -0,0 +1,132 @@ +import { notFound } from "next/navigation"; +import { requireProjectAccess } from "../../guards"; +import { canManageProject } from "@/lib/projects/authz"; +import { loadImportReadiness } from "@/lib/projects/import/readiness"; +import { + EMPTY_MAPPING_TARGETS, + loadMappingTargets, +} from "@/lib/projects/import/mappingTargets"; +import { ImportUpload } from "./components/ImportUpload"; +import { ImportSetupIncomplete } from "./components/ImportSetupIncomplete"; + +export const metadata = { + title: "Import programme data | Ara", +}; + +/** + * Work-order import, steps 1 and 2 of 3 — upload and parse (issue #414), then + * column mapping and value mapping (issue #415). + * + * Wireframes: `07-import-upload.html`, then `08-map-columns-rebuilt.html` and + * `09-map-columns-workstream-unlocked.html`. Both steps live behind this one + * route because the parsed file is held client-side (ADR-0020) — a separate + * mapping URL would drop it. Validation and commit (#417) follow; this page + * still writes nothing. + * + * Only internal and client-org managers may import, so this checks + * `canManageProject` rather than settling for the layout's view-level guard — + * a contractor with legitimate access to the project must not see the drop + * zone at all, not merely have their upload rejected by the route handler. + * + * The page is also **setup-gated** (ADR-0019): unless every selected workstream + * has a stage and a contractor, the drop zone is replaced by a "finish setup" + * state. The gate applies regardless of entry point — this route is reachable + * standalone from its own nav button today, and #413 will additionally route + * into it as the final step of the setup wizard, so it must not assume it is + * only ever reached once setup is known-complete. + */ + +/** + * Where the "finish setup" state sends the user. The concrete per-step wizard + * routes (select workstreams / configure stages / assign contractors) are + * owned by other issues; this points at the project's configuration home, and + * #413 can narrow it to a deep link when those routes firm up. + */ +function setupHref(projectId: string): string { + return `/projects/${projectId}/settings`; +} + +export default async function ImportPage(props: { + params: Promise<{ projectId: string }>; +}) { + const { projectId } = await props.params; + // The guard resolves the user, parses the id and enforces *view* access, + // 404-ing a junk id or a project outside the user's organisation. + const { user, project } = await requireProjectAccess(projectId); + + // Import is stricter than viewing: only internal and client-org managers may + // import, so a contractor with legitimate view access must not see the drop + // zone at all. 404 rather than 403, so project existence stays private. + if (!canManageProject(user, project)) notFound(); + + // Read-only: gather whether the project is set up enough to import against, + // and — when it is — what the file's values may be mapped to. The targets are + // loaded here, on the server, rather than fetched by the mapping step: they + // are the project's own configuration, they cannot change mid-import, and a + // gated project has nothing to map to anyway. + const readiness = await loadImportReadiness(project.id); + const targets = readiness.ready + ? await loadMappingTargets(project.id) + : EMPTY_MAPPING_TARGETS; + + return ( +
+
+

+ Work-order import · Steps 1–2 of 3 +

+

+ Import programme data +

+

+ Upload a file listing which workstreams each property takes and which + contractor delivers each — one row per property and workstream. A + property taking Windows and Doors appears twice, sharing its + identifier. +

+
+ + {readiness.ready ? ( + + ) : ( + + )} + +
+ {[ + { + title: "Upload & parse", + body: "We read your file and show you the columns and a sample of the rows.", + }, + { + title: "Column mapping", + body: "Match your headings to the fields we expect.", + }, + { + title: "Validate & commit", + body: "Review what will be created before anything is written.", + }, + ].map((step, i) => ( +
+

+ Step {i + 1} +

+

+ {step.title} +

+

{step.body}

+
+ ))} +
+
+ ); +} diff --git a/src/app/projects/[projectId]/layout.tsx b/src/app/projects/[projectId]/layout.tsx index 5ebf7d74..4c9c287a 100644 --- a/src/app/projects/[projectId]/layout.tsx +++ b/src/app/projects/[projectId]/layout.tsx @@ -1,6 +1,6 @@ import * as React from "react"; import { ProjectsNav, type ProjectsNavItem } from "../components/ProjectsNav"; -import { requireProjectAccess } from "../authz"; +import { requireProjectAccess } from "../guards"; function projectNav(projectId: string): ProjectsNavItem[] { const base = `/projects/${projectId}`; diff --git a/src/app/projects/[projectId]/page.tsx b/src/app/projects/[projectId]/page.tsx index e84d40da..d48e370d 100644 --- a/src/app/projects/[projectId]/page.tsx +++ b/src/app/projects/[projectId]/page.tsx @@ -1,25 +1,67 @@ -import { requireProjectAccess } from "../authz"; +import { notFound } from "next/navigation"; +import { requireProjectAccess } from "../guards"; +import { loadDashboardData } from "@/app/repositories/projects/dashboardRepository"; +import { buildStageLadders } from "@/lib/projects/derivations"; +import { summariseDashboard } from "@/lib/projects/dashboardSummary"; +import { + ContractorsTable, + KpiBand, + NeedsAttentionBand, + RecentWorkOrders, + WorkstreamsTable, +} from "./components/DashboardBands"; export const metadata = { title: "Project dashboard | Ara", }; +/** How many work orders the "Recent work orders" band shows. */ +const RECENT_LIMIT = 10; + /** - * Project dashboard shell. + * Programme dashboard (issue #418) — a Server Component over SQL aggregates. * - * Renders the frame only. The Workstream / Stage / Work order content is built - * in later issues, once the visibility rule (#408) and the workstream + - * project_type seed data (#407) are in place. + * The numbers here are grouped counts computed in the database, then folded by + * the pure `@/lib/projects/dashboardSummary` using the shared rules in + * `@/lib/projects/derivations`. Nothing on this page re-states what *complete*, + * *overdue* or *evidence completeness* mean — that is the whole point of the + * derivations module, which #419's work-orders table reuses so the two surfaces + * reconcile. + * + * Note the single `asOf` below: it is passed to both the SQL aggregate (bound + * as a date parameter, not `CURRENT_DATE`) and the JS rules, so every overdue + * number on the page is measured against the same day even if the render + * straddles midnight. + * + * Authorization runs through the route guard in `../guards` (#409, #439), + * which resolves the user, parses the `[projectId]` segment and enforces + * visibility — a junk id or a project the user may not see becomes a 404 + * inside the guard. This page adds no permission logic of its own; it reads + * the guaranteed-valid `project.id` back from the guard rather than parsing the + * segment a second time. */ export default async function ProjectDashboardPage(props: { params: Promise<{ projectId: string }>; }) { const { projectId } = await props.params; - await requireProjectAccess(projectId); + const { project } = await requireProjectAccess(projectId); + + const asOf = new Date(); + const data = await loadDashboardData(project.id, asOf, RECENT_LIMIT); + if (!data) notFound(); + + const ladders = buildStageLadders(data.stages); + const summary = summariseDashboard( + ladders, + data.groups, + new Map(data.workstreams.map((w) => [w.id, w.name])), + ); + + const workOrdersHref = `/projects/${projectId}/work-orders`; return ( -
-
+
+

Ara Projects

@@ -27,19 +69,19 @@ export default async function ProjectDashboardPage(props: { className="text-3xl font-extrabold text-gray-900 tracking-tight" data-testid="project-dashboard-heading" > - Project dashboard + {data.project.name} -

{projectId}

-
+

Programme dashboard

+ -
-

- Dashboard coming soon -

-

- Workstreams, stages and work orders will appear here. -

-
+ + + + +
); } diff --git a/src/app/projects/[projectId]/settings/components/ProjectDetailsForm.tsx b/src/app/projects/[projectId]/settings/components/ProjectDetailsForm.tsx new file mode 100644 index 00000000..f503ed16 --- /dev/null +++ b/src/app/projects/[projectId]/settings/components/ProjectDetailsForm.tsx @@ -0,0 +1,279 @@ +"use client"; + +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useMutation } from "@tanstack/react-query"; +import { useRouter } from "next/navigation"; +import { + projectDetailsToFormValues, + updateProjectSchema, + type ProjectDetails, + type UpdateProjectFormValues, +} from "@/lib/projects/updateProject"; +import type { SelectOption } from "@/lib/projects/createProject"; +import { DateInput } from "@/app/components/DateInput"; +import { Button } from "@/app/shadcn_components/ui/button"; +import { Checkbox } from "@/app/shadcn_components/ui/checkbox"; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/app/shadcn_components/ui/form"; +import { Input } from "@/app/shadcn_components/ui/input"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/app/shadcn_components/ui/select"; + +/** + * The HTTP call, kept outside the component so the component contains no + * `fetch` — TanStack Query owns the request lifecycle. Route handlers answer + * errors as `{ error: string }`, so a failure surfaces the server's own message. + */ +async function updateProject( + projectId: string, + values: UpdateProjectFormValues, +): Promise<{ id: string }> { + const response = await fetch(`/api/projects/${projectId}`, { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(values), + }); + + const body = await response.json().catch(() => null); + if (!response.ok) { + throw new Error(body?.error ?? "Could not save the project details"); + } + return body; +} + +export interface ProjectDetailsFormProps { + details: ProjectDetails; + projectTypes: SelectOption[]; +} + +/** + * Edit a project's details from the settings hub (issue #444). + * + * The same six fields the create-project modal collects, minus the owning + * organisation — re-homing a project would change who can see it, so it is + * shown read-only rather than offered as an edit (see `updateProjectSchema`). + * The resolver is `updateProjectSchema`, which is derived from + * `createProjectSchema`, so the two forms validate identically. + * + * On success the form resets to the values it just saved — which clears the + * dirty state and makes the Save button correctly go quiet — and + * `router.refresh()` re-renders the server component above it, so the heading + * and the readiness panel reflect the edit without a full reload. + */ +export function ProjectDetailsForm({ + details, + projectTypes, +}: ProjectDetailsFormProps) { + const router = useRouter(); + + const form = useForm({ + resolver: zodResolver(updateProjectSchema), + defaultValues: projectDetailsToFormValues(details), + }); + + const mutation = useMutation( + (values: UpdateProjectFormValues) => updateProject(details.id, values), + { + onSuccess: (_data, values) => { + form.reset(values); + router.refresh(); + }, + }, + ); + + return ( +
+

Project details

+

+ What this programme of works is called, who it is for, and when it runs. +

+ +
+ mutation.mutate(values))} + className="mt-4 space-y-4 rounded-xl border border-gray-200 bg-white p-6" + data-testid="project-details-form" + > + ( + + Project name + + + + + + )} + /> + + + Client +

+ {details.organisationName ?? "—"} +

+ + A project cannot be moved to another organisation — that would + change who can see it. + +
+ + ( + + Project type + + + + )} + /> + + ( + + Description + +