/** Add scan GPS and transfer metadata, preserving all existing schema fields. * DRY RUN: node --env-file=.env.local node_modules/tsx/dist/cli.mjs scripts/migrations/2026-10-17-clock-scan-location.mts * APPLY: append --apply --backup /absolute/path/clock-events-schema.json * Only schema changes; never changes worker, event or hour records. */ import PocketBase from "pocketbase"; import { writeFile, mkdir } from "node:fs/promises"; import { dirname } from "node:path"; const pb = new PocketBase(process.env.NEXT_PUBLIC_POCKETBASE_URL); if (process.env.POCKETBASE_ADMIN_TOKEN) pb.authStore.save(process.env.POCKETBASE_ADMIN_TOKEN); else await pb.collection("_superusers").authWithPassword(process.env.POCKETBASE_ADMIN_EMAIL!,process.env.POCKETBASE_ADMIN_PASSWORD!); const collection = await pb.collections.getOne("clock_events"); const additions = [ {name:"has_location",type:"bool"}, {name:"latitude",type:"number",min:-90,max:90}, {name:"longitude",type:"number",min:-180,max:180}, {name:"location_accuracy_m",type:"number",min:0}, {name:"is_transfer",type:"bool"}, {name:"previous_unclosed_in",type:"relation",collectionId:collection.id,maxSelect:1,cascadeDelete:false}, {name:"supervisor_note",type:"text",max:2000}, {name:"office_note",type:"text",max:2000}, {name:"office_resolved_at",type:"date"}, {name:"office_resolved_by",type:"text",max:128}, ]; for (const field of additions) { const existing = collection.fields.find((item:{name:string})=>item.name===field.name); if (existing && existing.type !== field.type) throw new Error(`Unexpected type for ${field.name}`); } const missing = additions.filter(field=>!collection.fields.some((item:{name:string})=>item.name===field.name)); console.log(JSON.stringify({mode:process.argv.includes("--apply")?"apply":"dry-run",collection:collection.name,addFields:missing.map(field=>field.name)})); if (process.argv.includes("--apply") && missing.length) { const backup = process.argv[process.argv.indexOf("--backup")+1]; if (!process.argv.includes("--backup") || !backup) throw new Error("--apply requires --backup PATH"); await mkdir(dirname(backup),{recursive:true}); await writeFile(backup,JSON.stringify(collection,null,2),{flag:"wx"}); await pb.collections.update(collection.id,{fields:[...collection.fields,...missing]}); const verified = await pb.collections.getOne(collection.id); for (const field of additions) if (!verified.fields.some((item:{name:string;type:string})=>item.name===field.name&&item.type===field.type)) throw new Error(`Schema verification failed: ${field.name}`); console.log("Verified additive schema update. No attendance records were changed."); }