WFDASH-WEBAPP/scripts/migrations/2026-09-04-create-pos-slip-layouts.ts
Dave 1bd659869d chore(pos): add pos_slip_layouts PB collection for the slip layout editor
One row per letterhead, holding the reorderable/toggleable block
list for each thermal slip (sale, delivery note, cash-up) plus the
delivery note's default pricing toggle. Migration already run
against the live PocketBase instance.
2026-09-04 12:46:17 +02:00

106 lines
3.3 KiB
TypeScript

/**
* One-shot migration: create the `pos_slip_layouts` collection.
*
* Run with:
*
* npx tsx scripts/migrations/2026-09-04-create-pos-slip-layouts.ts
*
* One row per letterhead, holding the till's reorderable/toggleable
* block list for each of the three thermal slips (sale, delivery
* note, cash-up) plus the delivery note's "show pricing" default.
* A new collection rather than a field on `letterhead_settings`
* because that collection is shared with the main WFDASH PDF-quote
* flow — POS-only slip layout has no business being coupled to it.
* See docs/superpowers/specs/2026-09-04-pos-slip-layout-editor-design.md.
*
* Idempotent — safe to re-run; exits early if the collection exists.
*
* Rollback: delete the `pos_slip_layouts` collection in the PB admin
* UI. No other collection references it, so nothing else is affected.
*/
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;
async function main() {
if (!ADMIN_EMAIL || !ADMIN_PASSWORD) {
throw new Error(
"Set PB_ADMIN_EMAIL and PB_ADMIN_PASSWORD env vars (e.g. sourced from .env.local)."
);
}
const pb = new PocketBase(PB_URL);
await pb.collection("_superusers").authWithPassword(ADMIN_EMAIL, ADMIN_PASSWORD);
console.log(`[pos-slip-layouts] Authenticated against ${PB_URL}`);
const existing = await pb.collections
.getFullList()
.then((all) => all.find((c) => c.name === "pos_slip_layouts"));
if (existing) {
console.log("[pos-slip-layouts] pos_slip_layouts already exists — skipping.");
return;
}
const letterhead = await pb.collections.getOne("letterhead_settings");
await pb.collections.create({
name: "pos_slip_layouts",
type: "base",
// Mirrors letterhead_settings' own rules — any authenticated PB
// user (the POS app itself only ever talks to this through the
// admin-authenticated service layer, same as letterhead_settings).
listRule: "@request.auth.id != ''",
viewRule: "@request.auth.id != ''",
createRule: "@request.auth.id != ''",
updateRule: "@request.auth.id != ''",
deleteRule: "@request.auth.id != ''",
fields: [
{
name: "letterhead",
type: "relation",
required: true,
collectionId: letterhead.id,
cascadeDelete: true,
minSelect: 1,
maxSelect: 1,
},
{
name: "sale_blocks",
type: "json",
required: false,
maxSize: 0,
},
{
name: "delivery_blocks",
type: "json",
required: false,
maxSize: 0,
},
{
name: "cashup_blocks",
type: "json",
required: false,
maxSize: 0,
},
{
name: "delivery_show_pricing",
type: "bool",
required: false,
},
],
// One layout row per letterhead.
indexes: [
"CREATE UNIQUE INDEX idx_pos_slip_layouts_letterhead ON pos_slip_layouts (letterhead)",
],
});
console.log("[pos-slip-layouts] Created pos_slip_layouts collection. Migration complete.");
}
main().catch((err) => {
console.error("[pos-slip-layouts] Migration failed:", err);
process.exit(1);
});