/// // Persönliche Einladungen — der zweite Weg zu einem Konto. // // Bis hierher gab es zwei Wege ins Team, und einer davon war schief: // // 1. Der Einladungslink. Er gilt für jeden, der ihn hat; wer ihn einlöst, // legt sich selbst ein Konto an und vergibt sein eigenes Passwort. // Dieser Weg bleibt unverändert. // // 2. „Konto anlegen" im Kader. Dort tippte die Teamleitung eine Adresse // und ein Passwort ein — und musste dieses Passwort anschließend // irgendwie zum Fahrer bringen. Über einen Kanal, den niemand geplant // hat, im Zweifel per WhatsApp. Sie kannte es außerdem, und der Fahrer // hatte ein Passwort, das er sich nicht ausgesucht hat. // // Der zweite Weg wird zur Einladungsmail: Die Teamleitung gibt nur noch die // Adresse an, PocketBase verschickt einen Link, und der Fahrer setzt sein // Passwort selbst. Niemand außer ihm kennt es je. // // Dafür bekommt `team_invites` drei Felder. Eine persönliche Einladung ist // derselbe Datensatz wie ein Link, nur mit Adressat: // // email — an wen sie ging. Gesetzt heißt: Diese Einladung gilt nur für // diese Adresse, die Anmeldeseite lässt keine andere zu. // rider — welcher Fahrer sein Konto bekommt. Ohne dieses Feld legte der // Beitritt einen zweiten Fahrer an und dieselbe Person stünde // doppelt im Kader. cascadeDelete: Verschwindet der Fahrer, // verfällt seine Einladung mit ihm. // sent — wann die Mail rausging. Nur zur Anzeige („vor 3 Tagen // eingeladen"), damit niemand raten muss, ob schon eine unterwegs // ist. // // Alle drei sind optional. Ein Einladungslink lässt sie leer und verhält // sich wie zuvor — die Felder erweitern den Datensatz, sie verändern ihn // nicht. migrate((app) => { const invites = app.findCollectionByNameOrId('team_invites') const riders = app.findCollectionByNameOrId('riders') if (!invites.fields.getByName('email')) { invites.fields.add(new Field({ id: 'email_invite_email', name: 'email', type: 'text', })) } if (!invites.fields.getByName('rider')) { invites.fields.add(new Field({ id: 'relation_invite_rider', name: 'rider', type: 'relation', required: false, maxSelect: 1, collectionId: riders.id, cascadeDelete: true, })) } if (!invites.fields.getByName('sent')) { invites.fields.add(new Field({ id: 'date_invite_sent', name: 'sent', type: 'date', })) } // Die createRule bleibt, wie sie ist: Einladungen legt die Teamleitung // an. Persönliche entstehen ohnehin nicht über die Collection, sondern // über POST /api/team-invites/send — der Hook prüft dieselbe Bedingung // und verschickt in einem Zug die Mail. app.save(invites) }, (app) => { const invites = app.findCollectionByNameOrId('team_invites') invites.fields.removeByName('email') invites.fields.removeByName('rider') invites.fields.removeByName('sent') app.save(invites) })