/** * Migration — add the `notes` field to `raw_price_list`. * * The `file_name` field already exists in the live PB (added by the * operator via the admin UI). This script is idempotent: it checks * for the field first and only adds it if missing. * * The `notes` field carries free-text operator instructions for the AI * extraction step — e.g. "Brand is JEI. Apply 30% markup. All prices * in ZAR excl. VAT. POA for any missing values." The n8n workflow's * LLM user message is built from this + the supplier name. * * Run with: * npm run pb:migrate:pricelist-notes */ import PocketBase from "pocketbase"; const PB_URL = process.env.NEXT_PUBLIC_POCKETBASE_URL || "http://127.0.0.1:8090"; const ADMIN_EMAIL = process.env.PB_ADMIN_EMAIL; const ADMIN_PASSWORD = process.env.PB_ADMIN_PASSWORD; if (!ADMIN_EMAIL || !ADMIN_PASSWORD) { throw new Error("PB_ADMIN_EMAIL and PB_ADMIN_PASSWORD are required."); } async function main() { const pb = new PocketBase(PB_URL); await pb.collection("_superusers").authWithPassword(ADMIN_EMAIL, ADMIN_PASSWORD); const cols = await pb.collections.getFullList(); const raw = cols.find((c) => c.name === "raw_price_list"); if (!raw) { throw new Error( "raw_price_list collection not found. Run `npm run pb:migrate:raw-price-list` first.", ); } const hasNotes = raw.fields.some((f) => f.name === "notes"); if (hasNotes) { console.log("raw_price_list.notes already exists, skipping."); return; } // Append the notes field. PB requires us to send the full field // list (not a partial patch), so we copy all existing fields and // tack on the new one. const updatedFields = [ ...raw.fields, { name: "notes", type: "text", required: false, options: { max: 0 } }, ]; await pb.collections.update(raw.id, { fields: updatedFields }); console.log("Added raw_price_list.notes"); console.log("Pricelist notes migration complete."); } main().catch((err) => { console.error(err); process.exit(1); });