Merge branch 'main' of github.com:Hestia-Homes/assessment-model

This commit is contained in:
Jun-te Kim 2026-06-29 10:54:51 +00:00
commit 0321a0101e
8 changed files with 34809 additions and 0 deletions

View file

@ -0,0 +1 @@
ALTER TABLE "property" ADD COLUMN "marked_for_deletion" boolean DEFAULT false NOT NULL;

View file

@ -0,0 +1,13 @@
CREATE TABLE "epc_photovoltaic_array" (
"id" bigserial PRIMARY KEY NOT NULL,
"epc_property_id" bigint NOT NULL,
"array_index" integer NOT NULL,
"peak_power" real NOT NULL,
"pitch" integer NOT NULL,
"overshading" integer NOT NULL,
"orientation" integer
);
--> statement-breakpoint
ALTER TABLE "epc_floor_dimension" ADD COLUMN "is_exposed_floor" boolean DEFAULT false NOT NULL;--> statement-breakpoint
ALTER TABLE "epc_floor_dimension" ADD COLUMN "is_above_partially_heated_space" boolean DEFAULT false NOT NULL;--> statement-breakpoint
ALTER TABLE "epc_photovoltaic_array" ADD CONSTRAINT "epc_photovoltaic_array_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;

View file

@ -0,0 +1,8 @@
ALTER TABLE "epc_building_part" ADD COLUMN "wall_insulation_thermal_conductivity" jsonb;--> statement-breakpoint
ALTER TABLE "epc_building_part" ADD COLUMN "alt_wall_1_is_sheltered" boolean;--> statement-breakpoint
ALTER TABLE "epc_building_part" ADD COLUMN "alt_wall_2_is_sheltered" boolean;--> statement-breakpoint
ALTER TABLE "epc_main_heating_detail" ADD COLUMN "community_heating_boiler_fuel_type" integer;--> statement-breakpoint
ALTER TABLE "epc_main_heating_detail" ADD COLUMN "community_heating_chp_fraction" real;--> statement-breakpoint
ALTER TABLE "epc_property" ADD COLUMN "energy_pv_diverter_present" boolean DEFAULT false NOT NULL;--> statement-breakpoint
ALTER TABLE "epc_property" ADD COLUMN "heating_cylinder_volume_measured_l" integer;--> statement-breakpoint
ALTER TABLE "epc_property" ADD COLUMN "ventilation_air_permeability_ap50_m3_h_m2" real;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1702,6 +1702,27 @@
"when": 1782313328071,
"tag": "0243_oval_pestilence",
"breakpoints": true
},
{
"idx": 244,
"version": "7",
"when": 1782387040698,
"tag": "0244_unknown_puck",
"breakpoints": true
},
{
"idx": 245,
"version": "7",
"when": 1782491854452,
"tag": "0245_magenta_nomad",
"breakpoints": true
},
{
"idx": 246,
"version": "7",
"when": 1782498864047,
"tag": "0246_minor_lady_bullseye",
"breakpoints": true
}
]
}

View file

@ -155,6 +155,12 @@ export const property = pgTable(
// lodged data
lodgedSapPoints: real("lodged_sap_points"),
lodgedEpcRating: epcEnum("lodged_epc_rating"),
// Soft-delete marker. Hard deletes on `property` are expensive (cascading
// child rows, indexes), so callers flag a row here and reads filter it out;
// a separate cron job performs the physical delete later. NOT NULL so reads
// never deal with a tri-state — every live row is explicitly `false`.
markedForDeletion: boolean("marked_for_deletion").notNull().default(false),
},
(table) => [
uniqueIndex("uq_property_portfolio_uprn")
@ -533,6 +539,7 @@ export const epcProperty = pgTable(
energyPvBatteryCapacity: real("energy_pv_battery_capacity"),
energyWindTurbineHubHeight: real("energy_wind_turbine_hub_height"),
energyWindTurbineRotorDiameter: real("energy_wind_turbine_rotor_diameter"),
energyPvDiverterPresent: boolean("energy_pv_diverter_present").notNull().default(false),
// Heating config
heatingCylinderSize: jsonb("heating_cylinder_size"),
@ -544,6 +551,7 @@ export const epcProperty = pgTable(
heatingSecondaryFuelType: integer("heating_secondary_fuel_type"),
heatingSecondaryHeatingType: jsonb("heating_secondary_heating_type"),
heatingCylinderInsulationThicknessMm: integer("heating_cylinder_insulation_thickness_mm"),
heatingCylinderVolumeMeasuredL: integer("heating_cylinder_volume_measured_l"), // litres, nullable
heatingWwhrsIndexNumber1: integer("heating_wwhrs_index_number_1"),
heatingWwhrsIndexNumber2: integer("heating_wwhrs_index_number_2"),
heatingShowerOutletType: jsonb("heating_shower_outlet_type"),
@ -587,6 +595,7 @@ export const epcProperty = pgTable(
ventilationSuspendedTimberFloorSealed: boolean("ventilation_suspended_timber_floor_sealed"),
ventilationHasDraughtLobby: boolean("ventilation_has_draught_lobby"),
ventilationAirPermeabilityAp4M3HM2: real("ventilation_air_permeability_ap4_m3_h_m2"),
ventilationAirPermeabilityAp50M3HM2: real("ventilation_air_permeability_ap50_m3_h_m2"), // m³/h·m² @50Pa, nullable
ventilationMechanicalVentilationKind: text("ventilation_mechanical_ventilation_kind"),
},
(table) => [
@ -687,6 +696,8 @@ export const epcMainHeatingDetail = pgTable(
mainHeatingDataSource: integer("main_heating_data_source"),
condensing: boolean("condensing"),
weatherCompensator: boolean("weather_compensator"),
communityHeatingBoilerFuelType: integer("community_heating_boiler_fuel_type"), // SAP fuel code, nullable
communityHeatingChpFraction: real("community_heating_chp_fraction"), // 0..1 fraction, nullable
},
);
@ -712,6 +723,9 @@ export const epcBuildingPart = pgTable(
wallDryLined: boolean("wall_dry_lined"),
wallThicknessMm: integer("wall_thickness_mm"),
wallInsulationThickness: jsonb("wall_insulation_thickness"),
// Union[int,str] SAP code — JSONB to preserve int-vs-str on round-trip,
// matching wall_insulation_thickness / roof_insulation_thickness.
wallInsulationThermalConductivity: jsonb("wall_insulation_thermal_conductivity"), // nullable
// age band source
// Floor
@ -742,6 +756,7 @@ export const epcBuildingPart = pgTable(
altWall1InsulationType: integer("alt_wall_1_insulation_type"),
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)
// Alternative wall 2 (inlined)
altWall2Area: real("alt_wall_2_area"),
@ -750,6 +765,7 @@ export const epcBuildingPart = pgTable(
altWall2InsulationType: integer("alt_wall_2_insulation_type"),
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)
},
);
@ -770,6 +786,8 @@ export const epcFloorDimension = pgTable(
heatLossPerimeterM: real("heat_loss_perimeter_m").notNull(),
floorInsulation: integer("floor_insulation"),
floorConstruction: integer("floor_construction"),
isExposedFloor: boolean("is_exposed_floor").notNull().default(false),
isAbovePartiallyHeatedSpace: boolean("is_above_partially_heated_space").notNull().default(false),
},
);
@ -804,6 +822,24 @@ export const epcWindow = pgTable(
},
);
// ─── epc_photovoltaic_array ───────────────────────────────────────────────────
export const epcPhotovoltaicArray = pgTable(
"epc_photovoltaic_array",
{
id: bigserial("id", { mode: "bigint" }).primaryKey(),
epcPropertyId: bigint("epc_property_id", { mode: "bigint" })
.notNull()
.references(() => epcProperty.id),
arrayIndex: integer("array_index").notNull(), // preserves list order for round-trip equality
peakPower: real("peak_power").notNull(), // kWp, float (e.g. 3.24)
pitch: integer("pitch").notNull(), // SAP pitch CODE (categorical int, not degrees)
overshading: integer("overshading").notNull(), // SAP overshading CODE (categorical int)
orientation: integer("orientation"), // SAP orientation CODE, nullable
},
);
// ─── epc_energy_element ───────────────────────────────────────────────────────
export const epcEnergyElement = pgTable(