/// /** * Proposal fields on `cards`. * * Plan Puzzle v1: clients drag a card into a month slot and we record their * intent on three nullable fields rather than overwriting `target_date` * (which the owner controls). The owner sees the chip, accepts (which copies * the proposal into `target_date`), or dismisses (which clears it). * * The three fields are written and cleared together. A row with one set and * the others null is logically incoherent; nothing in the application writes * one without the others. See src/app/actions/plan/client-proposal.ts and * src/app/actions/plan/owner-plan.ts for the only writers. * * The partial index supports the owner-side "show me cards with pending * proposals" query without indexing the millions of empty proposals on the * rest of the table. * * REFERENCE ONLY — see pb_migrations/README.md. scripts/setup-remote.ts is * what runs. */ migrate( (app) => { const cards = app.findCollectionByNameOrId("cards"); const users = app.findCollectionByNameOrId("users"); cards.fields.add([ { name: "proposed_target_date", type: "date", required: false, presentable: false, hidden: false, system: false, }, { name: "proposed_by", type: "relation", required: false, collectionId: users.id, cascadeDelete: false, minSelect: 0, maxSelect: 1, presentable: false, hidden: false, system: false, }, { name: "proposed_at", type: "date", required: false, presentable: false, hidden: false, system: false, }, ]); const existing = new Set((cards.indexes as string[]) ?? []); const proposalIndex = "CREATE INDEX idx_cards_proposal ON cards (proposed_target_date) WHERE proposed_target_date IS NOT NULL"; if (!existing.has(proposalIndex)) { cards.indexes.push(proposalIndex); } return app.save(cards); }, (app) => { const cards = app.findCollectionByNameOrId("cards"); for (const name of [ "proposed_target_date", "proposed_by", "proposed_at", ]) { const field = cards.fields.find((f) => f.name === name); if (field) cards.fields.removeById(field.id); } const indexes = (cards.indexes as string[]) ?? []; const proposalIndex = "CREATE INDEX idx_cards_proposal ON cards (proposed_target_date) WHERE proposed_target_date IS NOT NULL"; cards.indexes = indexes.filter((i) => i !== proposalIndex); return app.save(cards); } );