migrate((app) => { function collectionExists(name) { try { app.findCollectionByNameOrId(name); return true; } catch { return false; } } // ── households ────────────────────────────────────────────────────────────── if (!collectionExists('households')) { const col = new Collection({ name: 'households', type: 'base', listRule: '', viewRule: '', createRule: '', updateRule: '', deleteRule: '', fields: [ { name: 'name', type: 'text', required: true }, { name: 'invite_token', type: 'text', required: true }, ], }); app.save(col); } const householdsId = app.findCollectionByNameOrId('households').id; // ── items ──────────────────────────────────────────────────────────────────── if (!collectionExists('items')) { const col = new Collection({ name: 'items', type: 'base', listRule: '', viewRule: '', createRule: '', updateRule: '', deleteRule: '', fields: [ { name: 'household', type: 'relation', required: true, collectionId: householdsId, cascadeDelete: true, maxSelect: 1 }, { name: 'name', type: 'text', required: true }, { name: 'description', type: 'text' }, { name: 'category', type: 'text' }, { name: 'quantity', type: 'number' }, { name: 'unit', type: 'text' }, { name: 'min_stock_threshold', type: 'number' }, { name: 'on_shopping_list', type: 'bool' }, { name: 'photo', type: 'file', maxSelect: 1, maxSize: 5242880 }, { name: 'storage_location', type: 'text' }, { name: 'shopping_location', type: 'text' }, { name: 'price', type: 'number' }, { name: 'expiry_date', type: 'date' }, { name: 'barcode', type: 'text' }, { name: 'added_by_device', type: 'text' }, ], }); app.save(col); } // ── shopping_list ──────────────────────────────────────────────────────────── if (!collectionExists('shopping_list')) { const col = new Collection({ name: 'shopping_list', type: 'base', listRule: '', viewRule: '', createRule: '', updateRule: '', deleteRule: '', fields: [ { name: 'household', type: 'relation', required: true, collectionId: householdsId, cascadeDelete: true, maxSelect: 1 }, { name: 'item_id', type: 'text' }, { name: 'name', type: 'text', required: true }, { name: 'suggested_quantity', type: 'number' }, { name: 'unit', type: 'text' }, { name: 'is_checked', type: 'bool' }, { name: 'checked_by_device', type: 'text' }, { name: 'auto_added', type: 'bool' }, ], }); app.save(col); } // ── members ────────────────────────────────────────────────────────────────── if (!collectionExists('members')) { const col = new Collection({ name: 'members', type: 'base', listRule: '', viewRule: '', createRule: '', updateRule: '', deleteRule: '', fields: [ { name: 'household', type: 'relation', required: true, collectionId: householdsId, cascadeDelete: true, maxSelect: 1 }, { name: 'device_id', type: 'text', required: true }, { name: 'device_name', type: 'text' }, { name: 'fcm_token', type: 'text' }, { name: 'notifications_enabled', type: 'bool' }, ], }); app.save(col); } }, (app) => { // rollback for (const name of ['members', 'shopping_list', 'items', 'households']) { try { app.delete(app.findCollectionByNameOrId(name)); } catch {} } });