fix merge request

This commit is contained in:
Jun-te Kim 2026-05-06 09:47:53 +00:00
commit f98a740ee7
18 changed files with 43335 additions and 61 deletions

View file

@ -3,64 +3,53 @@ FROM library/python:3.12-bookworm
ARG USER=vscode
ARG USER_UID=1000
ARG USER_GID=1000
ARG DEBIAN_FRONTEND=noninteractive
# Install system dependencies in a single layer
# Base CLI tooling (sudo, git, ripgrep/fd for editors, etc.).
RUN apt update && apt install -y --no-install-recommends \
<<<<<<< HEAD
sudo jq vim curl bash-completion iputils-ping \
&& apt autoremove -y \
=======
sudo jq vim curl bash-completion \
ripgrep fd-find git make unzip \
>>>>>>> main
&& rm -rf /var/lib/apt/lists/*
# Create the user and grant sudo privileges
RUN useradd -m -s /bin/bash ${USER} \
# Passwordless-sudo dev user (UID/GID injected from the host via compose).
RUN useradd -m -s /bin/bash -u ${USER_UID} ${USER} \
&& echo "${USER} ALL=(ALL) NOPASSWD: ALL" >/etc/sudoers.d/${USER} \
&& chmod 0440 /etc/sudoers.d/${USER}
# Install Node.js 22 (from NodeSource)
# Node 22 (NodeSource).
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
&& apt install -y nodejs \
&& node -v \
&& npm -v
&& apt install -y nodejs
# # Install aws
# RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
# RUN unzip awscliv2.zip
# RUN ./aws/install
# # Install terraform
# RUN apt-get update && sudo apt-get install -y gnupg software-properties-common
# RUN wget -O- https://apt.releases.hashicorp.com/gpg | \
# gpg --dearmor | \
# sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg > /dev/null
# RUN echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
# https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \
# tee /etc/apt/sources.list.d/hashicorp.list
# RUN apt update
# RUN apt-get install terraform
# RUN terraform -install-autocomplete
# Install Neovim (latest) + LazyVim deps
RUN curl -fsSL https://github.com/neovim/neovim/releases/latest/download/nvim-linux-x86_64.tar.gz \
| tar -xz -C /opt \
&& ln -s /opt/nvim-linux-x86_64/bin/nvim /usr/local/bin/nvim \
&& apt update && apt install -y --no-install-recommends \
ripgrep fd-find git make unzip \
# GitHub CLI — used by the postCreate skill installer to authenticate against
# private Hestia-Homes repos via the host's mounted ~/.config/gh.
RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
| dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
&& chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
> /etc/apt/sources.list.d/github-cli.list \
&& apt update && apt install -y gh \
&& rm -rf /var/lib/apt/lists/*
# Install Claude
# Download Neovim (latest release tarball from GitHub) and symlink onto PATH.
RUN curl -fsSL https://github.com/neovim/neovim/releases/latest/download/nvim-linux-x86_64.tar.gz \
| tar -xz -C /opt \
&& ln -s /opt/nvim-linux-x86_64/bin/nvim /usr/local/bin/nvim
USER ${USER}
# Bootstrap LazyVim starter config
# LazyVim starter config (.git stripped so the user owns the files).
RUN git clone https://github.com/LazyVim/starter /home/${USER}/.config/nvim \
&& rm -rf /home/${USER}/.config/nvim/.git
# Install Claude + plugins + skills
RUN curl -fsSL https://claude.ai/install.sh | bash \
&& export PATH="/home/${USER}/.local/bin:${PATH}" \
&& claude plugin marketplace add JuliusBrussee/caveman \
&& claude plugin install caveman@caveman
ENV PATH="/home/vscode/.local/bin:${PATH}"
# Download + install Claude Code CLI (installs to ~/.local/bin).
RUN curl -fsSL https://claude.ai/install.sh | bash
ENV PATH="/home/${USER}/.local/bin:${PATH}"
USER root
# Set the working directory
WORKDIR /workspaces/assessment-model
WORKDIR /workspaces/assessment-model

View file

@ -4,14 +4,24 @@
"service": "frontend",
"remoteUser": "vscode",
"workspaceFolder": "/workspaces/assessment-model",
"initializeCommand": "docker network create shared-dev 2>/dev/null || true",
"postStartCommand": "bash .devcontainer/post-install.sh",
"forwardPorts": [3000], # 3000 = Next.js
"appPort": ["3000:3000"], # For devcontainer shell
// Host preflight: ensure GitHub auth exists before we try to build.
// Either ~/.config/gh (from `gh auth login`) or a GITHUB_TOKEN env var.
"initializeCommand": "test -d \"$HOME/.config/gh\" || test -n \"$GITHUB_TOKEN\" || { echo >&2 'error: no GitHub auth found. Run `gh auth login && gh auth setup-git` on the host, or export GITHUB_TOKEN, then retry.'; exit 1; }",
// Install Domna's curated skill set (pinned to 0.0.5) into this workspace,
// then install npm deps. `gh repo clone` handles private-repo auth using
// the mounted host ~/.config/gh.
"postCreateCommand": "gh repo clone Hestia-Homes/agentic-toolkit /tmp/agentic-toolkit -- --branch 0.0.5 --depth 1 && bash /tmp/agentic-toolkit/setup.sh && npm install",
"forwardPorts": [3000],
"appPort": ["3000:3000"],
"mounts": [
// Optional, just makes getting from Downloads (local env) easier
"source=${localEnv:HOME},target=/workspaces/home,type=bind"
],
"customizations": {
"vscode": {
"settings": {

View file

@ -3,6 +3,7 @@ services:
build:
context: ..
dockerfile: .devcontainer/Dockerfile
# Match host UID/GID so files written in the container aren't root-owned.
args:
USER_UID: ${UID:-1000}
USER_GID: ${GID:-1000}
@ -13,8 +14,14 @@ services:
volumes:
- ..:/workspaces/assessment-model
- ~/.gitconfig:/home/vscode/.gitconfig:ro
# GitHub CLI auth from host (created by `gh auth login`). Used by the
# postCreate skill installer to clone private Hestia-Homes repos.
- ~/.config/gh:/home/vscode/.config/gh:ro
environment:
# Host SSH agent — for `git push` etc. inside the container.
- SSH_AUTH_SOCK=${SSH_AUTH_SOCK:-}
# Fallback HTTPS auth if ~/.config/gh isn't present on the host.
- GITHUB_TOKEN=${GITHUB_TOKEN:-}
networks:
- frontend-net
- shared-dev

View file

@ -1 +0,0 @@
npm install;

View file

@ -23,8 +23,6 @@ CONFIG_PATH="${REPO_ROOT}/.devcontainer/devcontainer.json"
VALID_COMMANDS=(up shell down rebuild)
# --- helpers ---------------------------------------------------------------
usage() {
sed -n '3,15p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
exit "${1:-0}"
@ -36,8 +34,7 @@ die() {
}
in_list() {
local needle="$1"
shift
local needle="$1"; shift
local item
for item in "$@"; do
[[ "${item}" == "${needle}" ]] && return 0
@ -52,10 +49,7 @@ container_id() {
--filter "label=devcontainer.config_file=${CONFIG_PATH}"
}
# --- argument parsing ------------------------------------------------------
[[ $# -eq 1 ]] || usage 1
COMMAND="$1"
in_list "${COMMAND}" "${VALID_COMMANDS[@]}" \
@ -65,8 +59,6 @@ in_list "${COMMAND}" "${VALID_COMMANDS[@]}" \
DC_ARGS=(--workspace-folder "${REPO_ROOT}")
# --- dispatch --------------------------------------------------------------
case "${COMMAND}" in
up)
echo ">> bringing up devcontainer"
@ -74,8 +66,6 @@ case "${COMMAND}" in
;;
shell)
# Auto-up if not already running. `devcontainer up` is idempotent —
# it reuses an existing container, so this is cheap on warm starts.
if [[ -z "$(container_id)" ]]; then
echo ">> devcontainer not running, bringing it up first"
devcontainer up "${DC_ARGS[@]}"

View file

@ -0,0 +1,2 @@
ALTER TABLE "epc_window" RENAME COLUMN "pvc_frame" TO "frame_material";--> statement-breakpoint
ALTER TABLE "epc_window" ALTER COLUMN "transmission_data_source" SET DATA TYPE text;

View file

@ -0,0 +1 @@
ALTER TABLE "epc_window" ALTER COLUMN "frame_material" DROP NOT NULL;

View file

@ -0,0 +1,2 @@
ALTER TABLE "epc_property" ADD COLUMN "uploaded_file_id" bigint;--> statement-breakpoint
ALTER TABLE "epc_property" ADD CONSTRAINT "epc_property_uploaded_file_id_uploaded_files_id_fk" FOREIGN KEY ("uploaded_file_id") REFERENCES "public"."uploaded_files"("id") ON DELETE no action ON UPDATE no action;

View file

@ -0,0 +1 @@
ALTER TABLE "epc_property" ADD CONSTRAINT "epc_property_uploaded_file_id_unique" UNIQUE("uploaded_file_id");

View file

@ -0,0 +1,10 @@
ALTER TABLE "hubspot_deal_data" ADD COLUMN "survey_type" text;--> statement-breakpoint
ALTER TABLE "hubspot_deal_data" ADD COLUMN "measures_for_pibi_ordered" text;--> statement-breakpoint
ALTER TABLE "hubspot_deal_data" ADD COLUMN "pibi_order_date" timestamp (6) with time zone;--> statement-breakpoint
ALTER TABLE "hubspot_deal_data" ADD COLUMN "pibi_completed_date" timestamp (6) with time zone;--> statement-breakpoint
ALTER TABLE "hubspot_deal_data" ADD COLUMN "property_halted_date" timestamp (6) with time zone;--> statement-breakpoint
ALTER TABLE "hubspot_deal_data" ADD COLUMN "property_halted_reason" text;--> statement-breakpoint
ALTER TABLE "hubspot_deal_data" ADD COLUMN "technical_approved_measures_for_install" text;--> statement-breakpoint
ALTER TABLE "hubspot_deal_data" ADD COLUMN "sent_to_installer_for_pricing" timestamp (6) with time zone;--> statement-breakpoint
ALTER TABLE "hubspot_deal_data" ADD COLUMN "domna_survey_required" boolean;--> statement-breakpoint
ALTER TABLE "hubspot_deal_data" ADD COLUMN "domna_survey_date" timestamp (6) with time zone;

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

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1310,6 +1310,41 @@
"when": 1777028605680,
"tag": "0186_equal_baron_zemo",
"breakpoints": true
},
{
"idx": 187,
"version": "7",
"when": 1777307158192,
"tag": "0187_mean_salo",
"breakpoints": true
},
{
"idx": 188,
"version": "7",
"when": 1777364161220,
"tag": "0188_wild_morph",
"breakpoints": true
},
{
"idx": 189,
"version": "7",
"when": 1777392468614,
"tag": "0189_high_leech",
"breakpoints": true
},
{
"idx": 190,
"version": "7",
"when": 1777392681924,
"tag": "0190_worried_drax",
"breakpoints": true
},
{
"idx": 191,
"version": "7",
"when": 1777560763716,
"tag": "0191_soft_ezekiel_stane",
"breakpoints": true
}
]
}

View file

@ -1,4 +1,4 @@
import { pgTable, uuid, text, timestamp } from "drizzle-orm/pg-core";
import { pgTable, uuid, text, timestamp, boolean } from "drizzle-orm/pg-core";
import { InferModel } from "drizzle-orm";
export const hubspotDealData = pgTable("hubspot_deal_data", {
@ -58,6 +58,17 @@ export const hubspotDealData = pgTable("hubspot_deal_data", {
confirmedSurveyTime: text("confirmed_survey_time"),
surveyedDate: timestamp("surveyed_date", { precision: 6, withTimezone: true }),
surveyType: text("survey_type"),
measuresForPibiOrdered: text("measures_for_pibi_ordered"),
pibiOrderDate: timestamp("pibi_order_date", { precision: 6, withTimezone: true }),
pibiCompletedDate: timestamp("pibi_completed_date", { precision: 6, withTimezone: true }),
propertyHaltedDate: timestamp("property_halted_date", { precision: 6, withTimezone: true }),
propertyHaltedReason: text("property_halted_reason"),
technicalApprovedMeasuresForInstall: text("technical_approved_measures_for_install"),
sentToInstallerForPricing: timestamp("sent_to_installer_for_pricing", { precision: 6, withTimezone: true }),
domnaSurveyRequired: boolean("domna_survey_required"),
domnaSurveyDate: timestamp("domna_survey_date", { precision: 6, withTimezone: true }),
createdAt: timestamp("created_at", { precision: 6, withTimezone: true })
.defaultNow()
.notNull(),

View file

@ -15,6 +15,7 @@ import { portfolio, PortfolioStatus } from "./portfolio";
import { InferModel } from "drizzle-orm";
import { materialTypeEnum } from "./materials";
import { sql } from "drizzle-orm";
import { uploadedFiles } from "./uploaded_files";
// This is a placeholder for the property schema
export interface PropertyMeta {
@ -422,6 +423,9 @@ export const epcProperty = pgTable(
portfolioId: bigint("portfolio_id", { mode: "bigint" })
// .notNull()
.references(() => portfolio.id),
uploadedFileId: bigint("uploaded_file_id", { mode: "bigint" })
.unique()
.references(() => uploadedFiles.id),
// Identity / admin
uprn: bigint("uprn", { mode: "bigint" }),
@ -733,7 +737,6 @@ export const epcWindow = pgTable(
.notNull()
.references(() => epcProperty.id),
pvcFrame: text("pvc_frame").notNull(),
glazingGap: text("glazing_gap").notNull(),
orientation: text("orientation").notNull(),
windowType: text("window_type").notNull(),
@ -744,12 +747,13 @@ export const epcWindow = pgTable(
windowLocation: text("window_location").notNull(),
windowWallType: text("window_wall_type").notNull(),
permanentShuttersPresent: boolean("permanent_shutters_present").notNull(),
frameMaterial: text("frame_material"),
frameFactor: real("frame_factor"),
permanentShuttersInsulated: text("permanent_shutters_insulated"),
// Transmission details (inlined)
transmissionUValue: real("transmission_u_value"),
transmissionDataSource: integer("transmission_data_source"),
transmissionDataSource: text("transmission_data_source"),
transmissionSolarTransmittance: real("transmission_solar_transmittance"),
},
);