diff --git a/backend/pb_migrations/1754500000_created_trails.js b/backend/pb_migrations/1754500000_created_trails.js index 7fe3dc7..4b650f9 100644 --- a/backend/pb_migrations/1754500000_created_trails.js +++ b/backend/pb_migrations/1754500000_created_trails.js @@ -5,8 +5,23 @@ // Reihenfolge ist wichtig: trails.current zeigt auf trail_versions, // trail_versions.trail zeigt zurück auf trails. Deshalb wird trails zuerst // OHNE current angelegt, dann trail_versions, und current danach ergänzt. +// +// 1754400000_init_schema.js wurde nachträglich als vollständiger Snapshot des +// Live-Schemas neu exportiert und enthält die trail-Collections seither +// bereits. Auf einer bestehenden Instanz fällt das nicht auf, weil beide +// Migrationen längst als angewendet vermerkt sind — auf einer frischen +// Datenbank laufen sie nacheinander und kollidieren am eindeutigen +// Collection-Namen. Deshalb der Guard: ist trails schon da, gibt es hier +// nichts zu tun. migrate((app) => { + try { + app.findCollectionByNameOrId('trails') + return + } catch { + // Noch nicht vorhanden — regulär anlegen. + } + const teams = app.findCollectionByNameOrId('teams') const users = app.findCollectionByNameOrId('users') @@ -128,14 +143,19 @@ migrate((app) => { app.save(versions) // --- trails.current nachtragen --------------------------------------- - trails.fields.add(new Field({ + // Frisch laden statt das Objekt von oben weiterzuverwenden: das aus + // `new Collection()` erzeugte Objekt gilt weiterhin als neu, ein zweites + // app.save() darauf liefe erneut als Insert und scheiterte am + // eindeutigen Collection-Namen. + const trailsSaved = app.findCollectionByNameOrId('trails') + trailsSaved.fields.add(new Field({ name: 'current', type: 'relation', maxSelect: 1, collectionId: versions.id, cascadeDelete: false, })) - app.save(trails) + app.save(trailsSaved) // --- trail_flags ------------------------------------------------------ const adminOnly = @@ -149,11 +169,12 @@ migrate((app) => { viewRule: 'team.users.id ?= @request.auth.id', createRule: adminOnly, updateRule: adminOnly, - // Löschen nur, solange kein Marker diesen Typ verwendet — sonst - // bliebe ein Pflichtfeld zurück, das ins Leere zeigt. - // Klammern nötig: && bindet stärker als || — ohne sie gälte die - // Marker-Prüfung nur für den admins-Zweig, nicht für owner. - deleteRule: '(' + adminOnly + ') && @collection.trail_markers.flag ?!= id', + // Hier bewusst ohne die Marker-Prüfung: trail_markers existiert an + // dieser Stelle noch nicht, eine @collection.trail_markers-Referenz + // ließe die Migration auf einer frischen Datenbank scheitern. + // Die verschärfte Regel setzt 1754500200_trail_flags_delete_rule.js + // nach, sobald trail_markers angelegt ist. + deleteRule: adminOnly, fields: [ teamScoped('team'), { name: 'label', type: 'text', required: true, max: 60 },