refactor(scripts): delete 20 one-off/legacy scripts

The scripts/ directory had accumulated 29 entries, half of which were
one-off fixes that had already done their job and several of which
were Supabase-era artifacts that don't apply now that the project
uses direct Postgres via `pg`.

Deleted (none referenced from package.json, CLAUDE.md, MEMORY.md,
.gitea/workflows/deploy.yml, db/seeds/, or src/):

Supabase-era one-offs (the project moved off Supabase JS/REST):
- apply-admin-create-stop.js (RPC installer against supabase.co)
- fix-archived-rls.js (RLS repair against supabase.co)
- seed.sh (pure supabase REST seeding)
- seed_tuxedo_tour.py (Python equivalent of the JS seed)

Codemods / lint fixers that ran once:
- fix-server-auth.js, fix-server-auth-ast.js
- fix-button-has-type.js, fix-control-has-associated-label.js

Versioned iteration history of one-off checks:
- check-stop-fns.js, check-stop-fns2.js, check-stop-fns3.js
- verify-stop-fns.js (only referenced by apply-admin-create-stop.js)

Other one-offs:
- cleanup-duplicate-stops.ts
- create-admin-user.ts, seed-admin.ts (superseded by provision-admin.ts)
- seed-tuxedo.ts (superseded by seed-tuxedo-2026.js)
- import-woo-to-route.ts (WooCommerce import, no longer used)
- upload-tuxedo-video.mjs, verify-email.ts, e2e-test.sh

Also updated one stale comment in src/actions/admin/users.ts that
referenced scripts/seed-admin.ts.

Kept (9 scripts, all live-referenced):
- migrate.js (package.json + deploy.yml + MEMORY.md)
- db-reset.js (package.json: db:reset)
- seed-tuxedo-2026.js (package.json: db:seed:tour)
- import-tuxedo-stops.ts (db/seeds preferred path)
- provision-admin.ts (CLAUDE.md production bootstrap)
- preflight-check.js, postflight-check.js (.gitea/workflows/deploy.yml)
- generate-pwa-icons.js, generate-pwa-screenshots.js (reproducible PWA
  build assets, referenced in design docs)

Verified: tsc clean, 174/175 tests pass (same baseline), package.json
scripts and deploy.yml all still resolve to kept scripts.
This commit is contained in:
Nora
2026-06-25 17:23:28 -06:00
parent a2285baeb4
commit a706746250
21 changed files with 1 additions and 2648 deletions
-262
View File
@@ -1,262 +0,0 @@
/**
* import-woo-to-route.ts - 2026 Season Import
*
* Reads Tuxedo_Corn_2026_Tour_Schedule-2.xlsx (Full Tour Schedule sheet) and produces:
* products.csv - 1 core pickup product
* stops.csv - 164 active stops
*
* Usage:
* npx tsx scripts/import-woo-to-route.ts \
* --xlsx "/path/to/Tuxedo_Corn_2026_Tour_Schedule-2.xlsx" \
* --brand 64294306-5f42-463d-a5e8-2ad6c81a96de \
* --output ./import-output
*/
import * as fs from "fs";
import * as path from "path";
import { parseArgs } from "util";
import ExcelJS from "exceljs";
// Types
interface ProductOutput {
name: string;
price: number;
type: "Pickup" | "Shipping" | "Pickup & Shipping";
description: string;
active: boolean;
image_url: string;
is_taxable: boolean;
}
interface StopOutput {
city: string;
state: string;
location: string;
date: string;
time: string;
address: string;
notes: string;
}
function slugify(s: string): string {
return s
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-|-$/g, "");
}
async function main() {
const args = parseArgs({
options: {
xlsx: { type: "string" },
brand: { type: "string" },
output: { type: "string", default: "./import-output" },
},
});
const xlsxPath = args.values.xlsx as string;
const brandId = args.values.brand as string;
const outputDir = args.values.output as string;
if (!xlsxPath || !brandId) {
console.error(
"Usage: npx tsx scripts/import-woo-to-route.ts --xlsx <path> --brand <uuid> [--output <dir>]"
);
process.exit(1);
}
if (!fs.existsSync(xlsxPath)) {
console.error("File not found: " + xlsxPath);
process.exit(1);
}
// Read Excel
// Row 0=title, Row1=subtitle, Row2=color-key, Row3=column-headers, Row4+=data
const wb = new ExcelJS.Workbook();
await wb.xlsx.readFile(xlsxPath);
const sheet = wb.getWorksheet(1);
if (!sheet) {
console.error("No worksheet found in file");
process.exit(1);
}
const allRows: (string | null | undefined)[][] = [];
sheet.eachRow((row) => {
allRows.push(row.values as (string | null | undefined)[]);
});
const colHeaders = (allRows[3] as string[]).map((h: unknown) => String(h ?? "").trim());
console.log("Column headers:", colHeaders);
const ci = (col: string) => colHeaders.indexOf(col);
const wkIdx = ci("Wk"), typeIdx = ci("Type"), datesIdx = ci("Dates"), dayIdx = ci("Day");
const cityIdx = ci("City / Location"), hostIdx = ci("Host / Venue");
const timeIdx = ci("Time"), truckIdx = ci("Truck"), statusIdx = ci("Status"), notesIdx = ci("Notes");
interface ScheduleRow {
wk: number; type: string; dates: string; day: string;
city: string; host: string; time: string; truck: string; status: string; notes: string;
}
const scheduleRows: ScheduleRow[] = [];
let currentWeek: { wk: number; type: string; dates: string; day: string } | null = null;
for (let i = 4; i < allRows.length; i++) {
const row = allRows[i] as (string | null | undefined)[];
if (!row) continue;
const wkVal = row[wkIdx];
const Day = String(row[dayIdx] ?? "").trim();
const City_Location = String(row[cityIdx] ?? "").trim();
const Status = String(row[statusIdx] ?? "").trim();
if (wkVal !== null && wkVal !== undefined && String(wkVal).trim() !== "") {
currentWeek = {
wk: Number(wkVal),
type: String(row[typeIdx] ?? "").trim(),
dates: String(row[datesIdx] ?? "").trim(),
day: Day,
};
}
if (!currentWeek) continue;
if (Status === "Off day") continue;
if (!City_Location) continue;
scheduleRows.push({
wk: currentWeek.wk, type: currentWeek.type, dates: currentWeek.dates,
day: Day || currentWeek.day,
city: City_Location,
host: String(row[hostIdx] ?? "").trim(),
time: String(row[timeIdx] ?? "").trim(),
truck: String(row[truckIdx] ?? "").trim(),
status: Status,
notes: String(row[notesIdx] ?? "").trim(),
});
}
const ACTIVE_STATUSES = ["✓ Confirmed", "🔴 Pre-sale live"];
const activeRows = scheduleRows.filter((r) => ACTIVE_STATUSES.includes(r.status));
console.log("\nSchedule rows: " + scheduleRows.length + " total | " + activeRows.length + " active\n");
// PRODUCTS -- one core product for all stops
const products: ProductOutput[] = [
{
name: "Olathe Sweet Corn -- 24 Ear Box",
price: 25,
type: "Pickup",
description:
"Fresh Olathe Sweet Corn pickup box. Add to cart, then choose your pickup stop at checkout. " +
"Available July-September 2026 at stops across Colorado, Wyoming, and New Mexico. " +
"See tuxedocorn.com for full schedule.",
active: true,
image_url:
"https://tuxedocorn.com/wp-content/uploads/2024/06/110260317_3494904527187819_6983832261179080791_n-1.jpg",
is_taxable: true,
},
];
console.log("[products] 1 core product: \"" + products[0].name + "\" at $" + products[0].price + "\n");
// STOPS -- one row per active schedule entry
const stops: StopOutput[] = [];
const seenStopKeys = new Set<string>();
for (const row of activeRows) {
if (!row.city) continue;
// Parse "City ST" or "City, ST" -> city + state
const cityRaw = row.city.replace(/--/g, "-").trim();
let city = cityRaw, state = "CO";
if (cityRaw.includes(",")) {
const parts = cityRaw.split(",").map((s: string) => s.trim());
const lastPart = parts[parts.length - 1] ?? "";
if (/^[A-Z]{2}$/.test(lastPart)) { city = parts.slice(0, -1).join(", ").trim(); state = lastPart; }
else city = parts.join(", ");
} else {
const tokens = cityRaw.split(/\s+/);
const lastToken = tokens[tokens.length - 1] ?? "";
if (/^[A-Z]{2}$/.test(lastToken)) { state = lastToken; city = tokens.slice(0, -1).join(" "); }
}
const stopKey = slugify(city + "-" + state + "-" + row.dates + "-" + row.time);
if (seenStopKeys.has(stopKey)) continue;
seenStopKeys.add(stopKey);
// Human-readable stop label = "Store (Time) | Truck T1"
const stopName = row.host + " (" + row.time + ")" + (row.truck ? " | Truck " + row.truck : "");
stops.push({
city,
state,
location: stopName,
date: row.dates, // week range -- set actual date in /admin/stops after import
time: row.time,
address: row.city + " | " + row.host,
notes: row.day + (row.notes ? " | " + row.notes : ""),
});
}
console.log("[stops] " + stops.length + " stops written\n");
// Show sample by week
const byWeek: Record<string, typeof stops> = {};
for (const s of stops) {
if (!byWeek[s.date]) byWeek[s.date] = [];
byWeek[s.date].push(s);
}
const weeks = Object.keys(byWeek).slice(0, 4);
for (const week of weeks) {
const ws = byWeek[week];
console.log(" " + week + " (" + ws.length + " stops):");
for (const s of ws.slice(0, 3)) {
console.log(" " + s.city + ", " + s.state + " | \"" + s.location + "\" | " + s.time);
}
}
// Write output CSVs
fs.mkdirSync(outputDir, { recursive: true });
function writeCSV(filename: string, header: string, rows: string[][]) {
const lines = rows.map((r) =>
r.map((c) => "\"" + String(c ?? "").replace(/\"/g, "\"\"") + "\"").join(",")
);
fs.writeFileSync(path.join(outputDir, filename), header + lines.join("\n"));
}
writeCSV(
"products.csv",
"name,price,type,description,active,image_url,is_taxable\n",
products.map((p) => [
p.name, String(p.price), p.type, p.description,
String(p.active), p.image_url, String(p.is_taxable),
])
);
writeCSV(
"stops.csv",
"city,state,location,date,time,address,notes\n",
stops.map((s) => [s.city, s.state, s.location, s.date, s.time, s.address, s.notes])
);
// Summary
console.log("\n============================================================");
console.log("IMPORT READY");
console.log("============================================================");
console.log("\nproducts.csv: 1 product (\"" + products[0].name + "\" @ $" + products[0].price + " Pickup)");
console.log("stops.csv: " + stops.length + " stops (confirmed + pre-sale only)");
console.log("\nOutput: " + outputDir + "/");
console.log("");
console.log(">>> NOTE: stops.csv 'date' field is a WEEK RANGE (e.g. Jul 22-28).");
console.log("After importing stops, visit /admin/stops to set the actual date for each stop.");
console.log("");
console.log("NEXT STEPS:");
console.log(" 1. Upload " + outputDir + "/products.csv via /admin/import -> type: products");
console.log(" 2. Upload " + outputDir + "/stops.csv via /admin/import -> type: stops");
console.log(" 3. Visit /admin/stops -- set each stop's actual date, verify address/time");
console.log(" 4. Visit /tuxedo -- verify product and stops appear\n");
console.log("Re-run: npx tsx scripts/import-woo-to-route.ts --xlsx \"" + xlsxPath + "\" --brand " + brandId + " --output " + outputDir + "\n");
}
main().catch(console.error);