← back to Homesonspec
auto-save: 2026-07-22T18:15:55 (4 files) — apps/web/src/app/search/SearchClient.tsx apps/web/src/lib/parse-search.ts packages/search/src/index.ts deploy-full.sh
008a9dea8b14e7b8d4044f66a247806abc3c65f8 · 2026-07-22 18:16:01 -0700 · Steve Abrams
Files touched
M apps/web/src/app/search/SearchClient.tsxM apps/web/src/lib/parse-search.tsA deploy-full.shM packages/search/src/index.ts
Diff
commit 008a9dea8b14e7b8d4044f66a247806abc3c65f8
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed Jul 22 18:16:01 2026 -0700
auto-save: 2026-07-22T18:15:55 (4 files) — apps/web/src/app/search/SearchClient.tsx apps/web/src/lib/parse-search.ts packages/search/src/index.ts deploy-full.sh
---
apps/web/src/app/search/SearchClient.tsx | 13 ++++++++++
apps/web/src/lib/parse-search.ts | 1 +
deploy-full.sh | 42 ++++++++++++++++++++++++++++++++
packages/search/src/index.ts | 19 ++++++++++++---
4 files changed, 72 insertions(+), 3 deletions(-)
diff --git a/apps/web/src/app/search/SearchClient.tsx b/apps/web/src/app/search/SearchClient.tsx
index 20bb3c4..6d03c9e 100644
--- a/apps/web/src/app/search/SearchClient.tsx
+++ b/apps/web/src/app/search/SearchClient.tsx
@@ -44,8 +44,21 @@ interface Facets {
builder: { value: string; label: string; count: number }[];
beds: { value: number; count: number }[];
homeType: { value: string; count: number }[];
+ state: { value: string; count: number }[];
}
+const STATE_NAMES: Record<string, string> = {
+ AL: "Alabama", AK: "Alaska", AZ: "Arizona", AR: "Arkansas", CA: "California", CO: "Colorado",
+ CT: "Connecticut", DE: "Delaware", FL: "Florida", GA: "Georgia", HI: "Hawaii", ID: "Idaho",
+ IL: "Illinois", IN: "Indiana", IA: "Iowa", KS: "Kansas", KY: "Kentucky", LA: "Louisiana",
+ ME: "Maine", MD: "Maryland", MA: "Massachusetts", MI: "Michigan", MN: "Minnesota", MS: "Mississippi",
+ MO: "Missouri", MT: "Montana", NE: "Nebraska", NV: "Nevada", NH: "New Hampshire", NJ: "New Jersey",
+ NM: "New Mexico", NY: "New York", NC: "North Carolina", ND: "North Dakota", OH: "Ohio", OK: "Oklahoma",
+ OR: "Oregon", PA: "Pennsylvania", RI: "Rhode Island", SC: "South Carolina", SD: "South Dakota",
+ TN: "Tennessee", TX: "Texas", UT: "Utah", VT: "Vermont", VA: "Virginia", WA: "Washington",
+ WV: "West Virginia", WI: "Wisconsin", WY: "Wyoming", DC: "Washington DC",
+};
+
const SORTS = [
{ value: "newest", label: "Newest" },
{ value: "price_asc", label: "Price ↑" },
diff --git a/apps/web/src/lib/parse-search.ts b/apps/web/src/lib/parse-search.ts
index 6d9cbc5..a51d0c3 100644
--- a/apps/web/src/lib/parse-search.ts
+++ b/apps/web/src/lib/parse-search.ts
@@ -36,6 +36,7 @@ export function parseSearchParams(searchParams: URLSearchParams): SearchParams {
hoaMax: num(searchParams.get("hoaMax")),
schoolDistrict: searchParams.get("schoolDistrict") ?? undefined,
state: searchParams.get("state") ?? undefined,
+ states: searchParams.getAll("st"),
city: searchParams.get("city") ?? undefined,
moveInByMonths: num(searchParams.get("moveInByMonths")),
sort: (searchParams.get("sort") as SearchParams["sort"]) ?? "newest",
diff --git a/deploy-full.sh b/deploy-full.sh
new file mode 100644
index 0000000..dab87c2
--- /dev/null
+++ b/deploy-full.sh
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+# Full deploy for the /yolo "Open Design" run: reskin + packages/search freshness
+# filter + Stage-3 verification engine + the additive DB migration.
+# ! bash ~/Projects/spechomes/deploy-full.sh
+set -euo pipefail
+KH=root@45.61.58.125; REMOTE=/root/Projects/spechomes; WEB=9975
+RP='export PATH=$PATH:/root/.npm-global/bin:/usr/local/bin; export $(grep -E "^DATABASE_URL=" '"$REMOTE"'/.env | head -1 | xargs)'
+
+echo "── 1/5 ship changed source (reskin + search + workers + prisma) ──"
+rsync -az --delete ~/Projects/spechomes/apps/web/src/ $KH:$REMOTE/apps/web/src/
+rsync -az --delete ~/Projects/spechomes/packages/search/src/ $KH:$REMOTE/packages/search/src/
+rsync -az --delete ~/Projects/spechomes/apps/workers/src/ $KH:$REMOTE/apps/workers/src/
+rsync -az ~/Projects/spechomes/apps/workers/package.json $KH:$REMOTE/apps/workers/package.json
+rsync -az --delete ~/Projects/spechomes/packages/database/prisma/ $KH:$REMOTE/packages/database/prisma/
+rsync -az ~/Projects/spechomes/design-system/ $KH:$REMOTE/design-system/
+echo " synced"
+
+echo "── 2/5 apply ADDITIVE migration to live DB (SourceRun + SourceRegistry cols) ──"
+ssh $KH "cd $REMOTE; $RP; pnpm --filter @spechomes/database exec prisma migrate deploy 2>&1 | grep -iE 'migration|applied|already|error' | head"
+
+echo "── 3/5 regenerate Prisma client ──"
+ssh $KH "cd $REMOTE; $RP; pnpm --filter @spechomes/database exec prisma generate 2>&1 | grep -iE 'Generated|error' | head -3"
+
+echo "── 4/5 rebuild web (must compile before restart) ──"
+BUILD=$(ssh $KH "cd $REMOTE; $RP; pnpm --filter @spechomes/web build 2>&1 | grep -iE 'Compiled successfully|Failed|Type error|error TS' | head -4")
+echo "$BUILD"
+if ! echo "$BUILD" | grep -qi 'Compiled successfully'; then
+ echo "❌ build did NOT report success — NOT restarting pm2 (old build still serving). Aborting."
+ exit 1
+fi
+
+echo "── 5/5 restart + verify ──"
+ssh $KH "cd $REMOTE; $RP
+pm2 restart spechomes-web --update-env >/dev/null; sleep 4
+echo -n ' local web → '; curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:$WEB/
+echo -n ' /map page → '; curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:$WEB/map
+echo -n ' /search page → '; curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:$WEB/search
+echo -n ' /api/map count → '; curl -s http://127.0.0.1:$WEB/api/map | python3 -c 'import sys,json;d=json.load(sys.stdin);print(d[\"total\"],\"markers,\",len(d[\"builders\"]),\"builder(s)\")'
+echo -n ' verify CLI ok? → '; pnpm --filter @spechomes/workers verify -- health 2>/dev/null | python3 -c 'import sys,json;d=json.load(sys.stdin);print(len(d),\"sources tracked\")' 2>/dev/null || echo 'verify CLI FAILED'
+echo -n ' public https → '; curl -s -o /dev/null -w '%{http_code}\n' https://homesonspec.com/map
+echo -n ' font shipped? → '; curl -s http://127.0.0.1:$WEB/ | grep -oiE 'fraunces|inter' | head -1 || echo '(font name not inlined — check rendered CSS)'"
+echo "✅ full deploy complete"
diff --git a/packages/search/src/index.ts b/packages/search/src/index.ts
index 99a5809..d61f5c6 100644
--- a/packages/search/src/index.ts
+++ b/packages/search/src/index.ts
@@ -30,7 +30,8 @@ export interface SearchParams {
ageRestricted?: boolean;
hoaMax?: number;
schoolDistrict?: string;
- state?: string;
+ state?: string; // single-state (e.g. location-derived)
+ states?: string[]; // multi-select state facet (Amazon-style rail)
city?: string;
moveInByMonths?: number; // move-in timeframe: ready or completing within N months
sort?: "newest" | "price_asc" | "price_desc" | "sqft_desc" | "closest";
@@ -101,7 +102,11 @@ export function buildWhere(params: SearchParams, bbox?: BBox): Prisma.InventoryH
...(params.statuses?.length ? { constructionStatus: { in: params.statuses as never[] } } : {}),
...(params.storiesEq !== undefined ? { stories: params.storiesEq } : {}),
...(params.garageMin !== undefined ? { garageSpaces: { gte: params.garageMin } } : {}),
- ...(params.state ? { state: params.state } : {}),
+ ...(params.states?.length
+ ? { state: { in: params.states } }
+ : params.state
+ ? { state: params.state }
+ : {}),
...(params.city ? { city: { equals: params.city, mode: "insensitive" } } : {}),
...(moveInCutoff
? {
@@ -215,7 +220,7 @@ export async function runFacets(params: SearchParams) {
const without = (key: keyof SearchParams): Prisma.InventoryHomeWhereInput =>
buildWhere({ ...params, [key]: undefined }, bbox);
- const [byStatus, byBuilder, byBeds, byType] = await Promise.all([
+ const [byStatus, byBuilder, byBeds, byType, byState] = await Promise.all([
prisma.inventoryHome.groupBy({
by: ["constructionStatus"],
where: without("statuses"),
@@ -236,6 +241,11 @@ export async function runFacets(params: SearchParams) {
where: without("homeTypes"),
_count: { _all: true },
}),
+ prisma.inventoryHome.groupBy({
+ by: ["state"],
+ where: without("states"),
+ _count: { _all: true },
+ }),
]);
const builders = await prisma.builder.findMany({
@@ -256,5 +266,8 @@ export async function runFacets(params: SearchParams) {
.sort((a, b) => (a.beds ?? 0) - (b.beds ?? 0))
.map((b) => ({ value: b.beds, count: b._count._all })),
homeType: byType.map((t) => ({ value: t.homeType, count: t._count._all })),
+ state: byState
+ .map((s) => ({ value: s.state, count: s._count._all }))
+ .sort((a, b) => b.count - a.count),
};
}
← ec6046b Contrarian gate fixes: guard auto-pause recovery (manual dis
·
back to Homesonspec
·
Amazon-style faceted search rail: State (multi-select, 50-st da530f2 →