Skip to content

Commit 6a8cd6c

Browse files
Kjubikstronkclaude
andcommitted
Bridge the two existing accounts through the membership change
Deploying the membership rules locked both existing accounts out of their own data: reads now require a members document and none existed yet, so the app showed "this account isn't on the list" the moment the rules went live. Rules take effect instantly; documents don't create themselves. A temporary isFounder() carries the two original UIDs until their members documents exist, and writes fall back to a 'founders' couple so the backfill can still stamp records in the meantime. Both go once everyone has a membership — the whole point of this change was to get UIDs out of the rules. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 45344d1 commit 6a8cd6c

1 file changed

Lines changed: 27 additions & 4 deletions

File tree

‎firestore.rules‎

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,30 @@ service cloud.firestore {
1616
/** Anyone who has been placed in a couple. */
1717
function isMember() {
1818
return request.auth != null
19-
&& exists(/databases/$(database)/documents/members/$(request.auth.uid));
19+
&& (exists(/databases/$(database)/documents/members/$(request.auth.uid))
20+
|| isFounder());
21+
}
22+
23+
/**
24+
* TEMPORARY BRIDGE — delete once every account has a members document.
25+
*
26+
* Membership is a document now, but the accounts that existed before this
27+
* change have none, and rules take effect the instant they're deployed.
28+
* Without this, the two original accounts are locked out of their own data
29+
* between deploying and creating those documents.
30+
*/
31+
function isFounder() {
32+
return request.auth.uid in [
33+
'Vo3u7ycmqoTmrEHtr52A46kgorN2',
34+
'4wb13TLNaXWxWZacX5Bo6tFk4KE3'
35+
];
36+
}
37+
38+
/** A founder with no members document yet still has a couple to write to. */
39+
function myCoupleOrFounder() {
40+
return exists(/databases/$(database)/documents/members/$(request.auth.uid))
41+
? myCouple()
42+
: 'founders';
2043
}
2144
2245
/** The caller's couple. */
@@ -56,12 +79,12 @@ service cloud.firestore {
5679
// allow read: if isMember() && resource.data.coupleId == myCouple();
5780
allow read: if isMember();
5881
59-
allow delete: if isMember() && resource.data.coupleId == myCouple();
82+
allow delete: if isMember() && resource.data.coupleId == myCoupleOrFounder();
6083
6184
// Both stamps are enforced here, so neither can be forged: the record
6285
// must belong to your couple, and must be signed by you.
6386
allow create: if isMember()
64-
&& request.resource.data.coupleId == myCouple()
87+
&& request.resource.data.coupleId == myCoupleOrFounder()
6588
&& request.resource.data.createdBy == request.auth.uid;
6689
6790
allow update: if isMember()
@@ -70,7 +93,7 @@ service cloud.firestore {
7093
// The backfill may set a couple on a record that has none. Nothing may
7194
// ever move a record from one couple to another.
7295
&& (resource.data.get('coupleId', null) == null
73-
? request.resource.data.coupleId == myCouple()
96+
? request.resource.data.coupleId == myCoupleOrFounder()
7497
: request.resource.data.coupleId == resource.data.coupleId);
7598
}
7699

0 commit comments

Comments
 (0)