diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 00000000..7b99cc77 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,8 @@ +{ + "permissions": { + "deny": [ + "Bash(npx drizzle-kit generate)", + "Bash(npx drizzle-kit push)" + ] + } +} diff --git a/src/app/db/migrations/meta/0156_snapshot.json b/src/app/db/migrations/meta/0156_snapshot.json index 6a77ed0a..a7a12e06 100644 --- a/src/app/db/migrations/meta/0156_snapshot.json +++ b/src/app/db/migrations/meta/0156_snapshot.json @@ -48,9 +48,7 @@ "postcode_search_postcode_unique": { "name": "postcode_search_postcode_unique", "nullsNotDistinct": false, - "columns": [ - "postcode" - ] + "columns": ["postcode"] } }, "policies": {}, @@ -123,12 +121,8 @@ "name": "aspect_condition_element_id_element_id_fk", "tableFrom": "aspect_condition", "tableTo": "element", - "columnsFrom": [ - "element_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["element_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -175,12 +169,8 @@ "name": "element_survey_id_property_condition_survey_id_fk", "tableFrom": "element", "tableTo": "property_condition_survey", - "columnsFrom": [ - "survey_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["survey_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -448,12 +438,8 @@ "name": "property_status_tracker_property_id_property_id_fk", "tableFrom": "property_status_tracker", "tableTo": "property", - "columnsFrom": [ - "property_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["property_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -461,12 +447,8 @@ "name": "property_status_tracker_portfolio_id_portfolio_id_fk", "tableFrom": "property_status_tracker", "tableTo": "portfolio", - "columnsFrom": [ - "portfolio_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["portfolio_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1241,12 +1223,8 @@ "name": "energy_assessment_documents_energy_assessment_id_energy_assessments_id_fk", "tableFrom": "energy_assessment_documents", "tableTo": "energy_assessments", - "columnsFrom": [ - "energy_assessment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["energy_assessment_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" }, @@ -1254,12 +1232,8 @@ "name": "energy_assessment_documents_scenario_id_energy_assessment_scenarios_id_fk", "tableFrom": "energy_assessment_documents", "tableTo": "energy_assessment_scenarios", - "columnsFrom": [ - "scenario_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["scenario_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -1299,12 +1273,8 @@ "name": "energy_assessment_scenarios_energy_assessment_id_energy_assessments_id_fk", "tableFrom": "energy_assessment_scenarios", "tableTo": "energy_assessments", - "columnsFrom": [ - "energy_assessment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["energy_assessment_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -1429,12 +1399,8 @@ "name": "files_from_surveyor_portfolio_id_portfolio_id_fk", "tableFrom": "files_from_surveyor", "tableTo": "portfolio", - "columnsFrom": [ - "portfolio_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["portfolio_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" }, @@ -1442,12 +1408,8 @@ "name": "files_from_surveyor_property_id_property_id_fk", "tableFrom": "files_from_surveyor", "tableTo": "property", - "columnsFrom": [ - "property_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["property_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -1525,12 +1487,8 @@ "name": "funding_package_plan_id_plan_id_fk", "tableFrom": "funding_package", "tableTo": "plan", - "columnsFrom": [ - "plan_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["plan_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -1595,12 +1553,8 @@ "name": "funding_package_measures_funding_package_id_funding_package_id_fk", "tableFrom": "funding_package_measures", "tableTo": "funding_package", - "columnsFrom": [ - "funding_package_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["funding_package_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" }, @@ -1608,12 +1562,8 @@ "name": "funding_package_measures_material_id_material_id_fk", "tableFrom": "funding_package_measures", "tableTo": "material", - "columnsFrom": [ - "material_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["material_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -1749,12 +1699,8 @@ "name": "inspections_property_id_property_id_fk", "tableFrom": "inspections", "tableTo": "property", - "columnsFrom": [ - "property_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["property_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -2205,12 +2151,8 @@ "name": "portfolioUsers_user_id_user_id_fk", "tableFrom": "portfolioUsers", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" }, @@ -2218,12 +2160,8 @@ "name": "portfolioUsers_portfolio_id_portfolio_id_fk", "tableFrom": "portfolioUsers", "tableTo": "portfolio", - "columnsFrom": [ - "portfolio_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["portfolio_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -2306,12 +2244,8 @@ "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" - ], + "columnsFrom": ["survey_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -2531,12 +2465,8 @@ "name": "property_portfolio_id_portfolio_id_fk", "tableFrom": "property", "tableTo": "portfolio", - "columnsFrom": [ - "portfolio_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["portfolio_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -2963,12 +2893,8 @@ "name": "property_details_epc_property_id_property_id_fk", "tableFrom": "property_details_epc", "tableTo": "property", - "columnsFrom": [ - "property_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["property_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" }, @@ -2976,12 +2902,8 @@ "name": "property_details_epc_portfolio_id_portfolio_id_fk", "tableFrom": "property_details_epc", "tableTo": "portfolio", - "columnsFrom": [ - "portfolio_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["portfolio_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -3179,12 +3101,8 @@ "name": "property_targets_property_id_property_id_fk", "tableFrom": "property_targets", "tableTo": "property", - "columnsFrom": [ - "property_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["property_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" }, @@ -3192,12 +3110,8 @@ "name": "property_targets_portfolio_id_portfolio_id_fk", "tableFrom": "property_targets", "tableTo": "portfolio", - "columnsFrom": [ - "portfolio_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["portfolio_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -3566,12 +3480,8 @@ "name": "plan_portfolio_id_portfolio_id_fk", "tableFrom": "plan", "tableTo": "portfolio", - "columnsFrom": [ - "portfolio_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["portfolio_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" }, @@ -3579,12 +3489,8 @@ "name": "plan_property_id_property_id_fk", "tableFrom": "plan", "tableTo": "property", - "columnsFrom": [ - "property_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["property_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" }, @@ -3592,12 +3498,8 @@ "name": "plan_scenario_id_scenario_id_fk", "tableFrom": "plan", "tableTo": "scenario", - "columnsFrom": [ - "scenario_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["scenario_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -3674,12 +3576,8 @@ "name": "plan_recommendations_plan_id_plan_id_fk", "tableFrom": "plan_recommendations", "tableTo": "plan", - "columnsFrom": [ - "plan_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["plan_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" }, @@ -3687,12 +3585,8 @@ "name": "plan_recommendations_recommendation_id_recommendation_id_fk", "tableFrom": "plan_recommendations", "tableTo": "recommendation", - "columnsFrom": [ - "recommendation_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["recommendation_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -3902,12 +3796,8 @@ "name": "recommendation_property_id_property_id_fk", "tableFrom": "recommendation", "tableTo": "property", - "columnsFrom": [ - "property_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["property_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -3995,12 +3885,8 @@ "name": "recommendation_materials_recommendation_id_recommendation_id_fk", "tableFrom": "recommendation_materials", "tableTo": "recommendation", - "columnsFrom": [ - "recommendation_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["recommendation_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -4008,12 +3894,8 @@ "name": "recommendation_materials_material_id_material_id_fk", "tableFrom": "recommendation_materials", "tableTo": "material", - "columnsFrom": [ - "material_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["material_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -4279,12 +4161,8 @@ "name": "scenario_portfolio_id_portfolio_id_fk", "tableFrom": "scenario", "tableTo": "portfolio", - "columnsFrom": [ - "portfolio_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["portfolio_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -4442,12 +4320,8 @@ "name": "solar_scenario_solar_id_solar_id_fk", "tableFrom": "solar_scenario", "tableTo": "solar", - "columnsFrom": [ - "solar_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["solar_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -4526,12 +4400,8 @@ "name": "sub_task_task_id_tasks_id_fk", "tableFrom": "sub_task", "tableTo": "tasks", - "columnsFrom": [ - "task_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["task_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -4690,12 +4560,8 @@ "name": "account_userId_user_id_fk", "tableFrom": "account", "tableTo": "user", - "columnsFrom": [ - "userId" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["userId"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -4703,10 +4569,7 @@ "compositePrimaryKeys": { "account_provider_providerAccountId_pk": { "name": "account_provider_providerAccountId_pk", - "columns": [ - "provider", - "providerAccountId" - ] + "columns": ["provider", "providerAccountId"] } }, "uniqueConstraints": {}, @@ -4743,12 +4606,8 @@ "name": "session_userId_user_id_fk", "tableFrom": "session", "tableTo": "user", - "columnsFrom": [ - "userId" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["userId"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -4840,9 +4699,7 @@ "user_email_unique": { "name": "user_email_unique", "nullsNotDistinct": false, - "columns": [ - "email" - ] + "columns": ["email"] } }, "policies": {}, @@ -4957,12 +4814,8 @@ "name": "user_profiles_user_id_user_id_fk", "tableFrom": "user_profiles", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -5001,10 +4854,7 @@ "compositePrimaryKeys": { "verificationToken_identifier_token_pk": { "name": "verificationToken_identifier_token_pk", - "columns": [ - "identifier", - "token" - ] + "columns": ["identifier", "token"] } }, "uniqueConstraints": {}, @@ -5298,12 +5148,7 @@ "public.scheme": { "name": "scheme", "schema": "public", - "values": [ - "eco4", - "gbis", - "whlg", - "none" - ] + "values": ["eco4", "gbis", "whlg", "none"] }, "public.inspection_archetype_2": { "name": "inspection_archetype_2", @@ -5320,22 +5165,12 @@ "public.inspection_archetype": { "name": "inspection_archetype", "schema": "public", - "values": [ - "Bungalow", - "Flat", - "Maisonette", - "House", - "non-domestic" - ] + "values": ["Bungalow", "Flat", "Maisonette", "House", "non-domestic"] }, "public.inspection_borescoped": { "name": "inspection_borescoped", "schema": "public", - "values": [ - "yes", - "no", - "refused" - ] + "values": ["yes", "no", "refused"] }, "public.inspections_access_issues": { "name": "inspections_access_issues", @@ -5417,11 +5252,7 @@ "public.inspections_tile_hung": { "name": "inspections_tile_hung", "schema": "public", - "values": [ - "yes", - "no", - "first floor flats are tile hung" - ] + "values": ["yes", "no", "first floor flats are tile hung"] }, "public.inspections_wall_construction": { "name": "inspections_wall_construction", @@ -5457,19 +5288,12 @@ "public.cost_unit": { "name": "cost_unit", "schema": "public", - "values": [ - "gbp_sq_meter", - "gbp_per_unit", - "gbp_per_m2", - "gbp_per_m" - ] + "values": ["gbp_sq_meter", "gbp_per_unit", "gbp_per_m2", "gbp_per_m"] }, "public.depth_unit": { "name": "depth_unit", "schema": "public", - "values": [ - "mm" - ] + "values": ["mm"] }, "public.type": { "name": "type", @@ -5522,26 +5346,17 @@ "public.r_value_unit": { "name": "r_value_unit", "schema": "public", - "values": [ - "square_meter_kelvin_per_watt" - ] + "values": ["square_meter_kelvin_per_watt"] }, "public.size_unit": { "name": "size_unit", "schema": "public", - "values": [ - "kWp", - "kW", - "watt", - "storey" - ] + "values": ["kWp", "kW", "watt", "storey"] }, "public.thermal_conductivity_unit": { "name": "thermal_conductivity_unit", "schema": "public", - "values": [ - "watt_per_meter_kelvin" - ] + "values": ["watt_per_meter_kelvin"] }, "public.goal": { "name": "goal", @@ -5557,12 +5372,7 @@ "public.role": { "name": "role", "schema": "public", - "values": [ - "creator", - "admin", - "read", - "write" - ] + "values": ["creator", "admin", "read", "write"] }, "public.status": { "name": "status", @@ -5583,32 +5393,17 @@ "public.epc": { "name": "epc", "schema": "public", - "values": [ - "A", - "B", - "C", - "D", - "E", - "F", - "G" - ] + "values": ["A", "B", "C", "D", "E", "F", "G"] }, "public.creation_status": { "name": "creation_status", "schema": "public", - "values": [ - "LOADING", - "READY", - "ERROR" - ] + "values": ["LOADING", "READY", "ERROR"] }, "public.housing_type": { "name": "housing_type", "schema": "public", - "values": [ - "Private", - "Social" - ] + "values": ["Private", "Social"] }, "public.measure_type": { "name": "measure_type", @@ -5654,26 +5449,17 @@ "public.unit_quantity": { "name": "unit_quantity", "schema": "public", - "values": [ - "m2", - "part", - "kwp" - ] + "values": ["m2", "part", "kwp"] }, "public.scenario_type": { "name": "scenario_type", "schema": "public", - "values": [ - "unit", - "building" - ] + "values": ["unit", "building"] }, "public.source": { "name": "source", "schema": "public", - "values": [ - "portfolio_id" - ] + "values": ["portfolio_id"] }, "public.user_profiles_property_count": { "name": "user_profiles_property_count", @@ -5725,4 +5511,4 @@ "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 ba14ddec..5092c886 100644 --- a/src/app/db/migrations/meta/_journal.json +++ b/src/app/db/migrations/meta/_journal.json @@ -1102,4 +1102,4 @@ "breakpoints": true } ] -} \ No newline at end of file +} diff --git a/src/app/db/schema/organisation.ts b/src/app/db/schema/organisation.ts new file mode 100644 index 00000000..2358104f --- /dev/null +++ b/src/app/db/schema/organisation.ts @@ -0,0 +1,17 @@ +import { pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core"; +import { InferModel } from "drizzle-orm"; + +export const organisation = pgTable("organisation", { + id: uuid("id").defaultRandom().primaryKey(), + createdAt: timestamp("created_at", { precision: 6, withTimezone: true }) + .defaultNow() + .notNull(), + updatedAt: timestamp("updated_at", { precision: 6, withTimezone: true }) + .defaultNow() + .notNull(), + hubspotCompanyId: text("hubspot_company_id"), + companyName: text("company_name"), +}); + +export type Organisation = InferModel; +export type NewOrganisation = InferModel; diff --git a/src/app/db/schema/team.ts b/src/app/db/schema/team.ts new file mode 100644 index 00000000..e89e1e20 --- /dev/null +++ b/src/app/db/schema/team.ts @@ -0,0 +1,59 @@ +import { pgTable, text, timestamp, uuid, bigint } from "drizzle-orm/pg-core"; +import { InferModel } from "drizzle-orm"; +import { organisation } from "./organisation"; +import { user } from "./users"; +import { portfolio, roleEnum } from "./portfolio"; + +export const team = pgTable("team", { + id: uuid("id").defaultRandom().primaryKey(), + teamName: text("team_name").notNull(), + orgId: uuid("org_id").notNull().references(() => organisation.id), + createdAt: timestamp("created_at", { precision: 6, withTimezone: true }) + .defaultNow() + .notNull(), + updatedAt: timestamp("updated_at", { precision: 6, withTimezone: true }) + .defaultNow() + .notNull(), +}); + +export const teamMembers = pgTable("team_members", { + id: uuid("id").defaultRandom().primaryKey(), + userId: bigint("user_id", { mode: "bigint" }) + .notNull() + .references(() => user.id), + teamId: uuid("team_id").notNull().references(() => team.id), + createdAt: timestamp("created_at", { precision: 6, withTimezone: true }) + .defaultNow() + .notNull(), + updatedAt: timestamp("updated_at", { precision: 6, withTimezone: true }) + .defaultNow() + .notNull(), +}); + +export const teamPortfolioPermissions = pgTable("team_portfolio_permissions", { + id: uuid("id").defaultRandom().primaryKey(), + teamId: uuid("team_id").notNull().references(() => team.id), + portfolioId: bigint("portfolio_id", { mode: "bigint" }) + .notNull() + .references(() => portfolio.id), + role: roleEnum("role").notNull(), + createdAt: timestamp("created_at", { precision: 6, withTimezone: true }) + .defaultNow() + .notNull(), + updatedAt: timestamp("updated_at", { precision: 6, withTimezone: true }) + .defaultNow() + .notNull(), +}); + +export type Team = InferModel; +export type NewTeam = InferModel; +export type TeamMembers = InferModel; +export type NewTeamMembers = InferModel; +export type TeamPortfolioPermissions = InferModel< + typeof teamPortfolioPermissions, + "select" +>; +export type NewTeamPortfolioPermissions = InferModel< + typeof teamPortfolioPermissions, + "insert" +>; 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 721571bd..692b7ef5 100644 --- a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/transforms.ts +++ b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/transforms.ts @@ -60,6 +60,7 @@ const STAGE_ID_MAP: Record = { "2769407184": "Queries", //[Ops] Talk to client, Needs Heating Upgrade (Pre EPR C) "2702650617": "AFTER_ASSESSMENT", //[Design] Ready for Design "2473886962": "AFTER_ASSESSMENT", //[Design] Design in progress + "1668803774": "AFTER_ASSESSMENT", //[Ops] post-ERF / completed coordination stage }; // ----------------------------------------------------------------------- @@ -94,7 +95,7 @@ function resolveAfterAssessmentStage( // Maps dealstage ID + coordinationStatus + designStatus -> DisplayStage // ----------------------------------------------------------------------- export function resolveDisplayStage(deal: HubspotDeal): DisplayStage { - const raw = STAGE_ID_MAP[deal.dealstage ?? ""] ?? "Unknown Stage"; + const raw = STAGE_ID_MAP[deal.dealstage ?? ""] ?? "AFTER_ASSESSMENT"; if (raw === "AFTER_ASSESSMENT") { return resolveAfterAssessmentStage(