leafittome/firestore.rules
cschlaefke 778b3bd34d V2.2: Besitzer-Konzept, Haushalte umbenennen, Austreten/Entfernen, Checkliste über alle Haushalte
- ownerUid je Haushalt (Alt-Haushalte: erster memberUids-Eintrag = Ersteller);
  Besitzer-Anzeige in Mitglieder- und Haushaltsliste
- Haushalt umbenennen (Dialog im Haushalts-Screen); Rules erlauben Clients am
  Haushalts-Dokument nur noch das Namensfeld
- Cloud Functions leaveHousehold (selbst austreten, auch als Sitter) und
  removeMember (nur Besitzer); beide biegen den aktiven Zeiger des Betroffenen
  um und legen notfalls einen frischen eigenen Haushalt an
- Haushalts-Wechsler im Drawer (PopupMenu, ab zwei Haushalten)
- Tages-Checkliste und nächste Fälligkeit aggregieren über alle Haushalte,
  mit Zwischenüberschrift je Haushalt; Bestätigen schreibt in den
  Herkunfts-Haushalt der Aufgabe
- Widget-Tests: Gruppierung, Besitzer-Rechte, Umbenennen

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 21:39:10 +02:00

86 lines
3.3 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

rules_version = '2';
// Sicherheitsregeln für LeafItToMe.
//
// Grundprinzip: Alle App-Daten hängen an einem Haushalt. Lesen darf nur,
// wer im Feld `memberUids` des Haushalts steht. Schreiben hängt zusätzlich
// von der Rolle ab: "member" darf alles, "sitter" (Pflanzen-Sitter) darf
// nur Aufgaben bestätigen. Das eigene Nutzer-Dokument sieht nur der Nutzer.
service cloud.firestore {
match /databases/{database}/documents {
function signedIn() {
return request.auth != null;
}
function householdData(householdId) {
return get(/databases/$(database)/documents/households/$(householdId)).data;
}
function isMember(householdId) {
return signedIn()
&& request.auth.uid in householdData(householdId).memberUids;
}
// Rolle des aufrufenden Nutzers. Haushalte aus der Zeit vor V2 haben
// noch keine members-Map dann gilt jeder Eingetragene als "member".
function roleOf(householdId) {
return householdData(householdId)
.get('members', {})
.get(request.auth.uid, {'role': 'member'})
.get('role', 'member');
}
// Eigenes Nutzerprofil (enthält u. a. die householdId).
match /users/{uid} {
allow read, write: if signedIn() && request.auth.uid == uid;
}
// Einladungscodes: Erstellen darf jedes Mitglied des jeweiligen
// Haushalts. Gelesen und eingelöst werden Codes ausschließlich über
// die Cloud Function joinHousehold (Admin-Rechte) Clients nie direkt.
match /invites/{code} {
allow create: if signedIn()
&& request.resource.data.createdBy == request.auth.uid
&& isMember(request.resource.data.householdId);
allow read, update, delete: if false;
}
match /households/{householdId} {
allow read: if signedIn() && request.auth.uid in resource.data.memberUids;
// Vom Client aus dürfen volle Mitglieder nur den Namen ändern;
// jede Mitglieder-Verwaltung (Beitritt, Austritt, Entfernen) läuft
// ausschließlich über Cloud Functions mit Admin-Rechten.
allow update: if signedIn()
&& request.auth.uid in resource.data.memberUids
&& resource.data.get('members', {})
.get(request.auth.uid, {'role': 'member'})
.get('role', 'member') == 'member'
&& request.resource.data.diff(resource.data).affectedKeys()
.hasOnly(['name']);
// Anlegen nur, wenn man sich selbst als Mitglied einträgt
// (passiert automatisch bei der Registrierung).
allow create: if signedIn()
&& request.auth.uid in request.resource.data.memberUids;
allow delete: if false;
match /plants/{plantId} {
allow read: if isMember(householdId);
allow create, delete: if isMember(householdId)
&& roleOf(householdId) == 'member';
// Sitter dürfen ausschließlich die Bestätigungs-Felder ändern.
allow update: if isMember(householdId)
&& (roleOf(householdId) == 'member'
|| request.resource.data.diff(resource.data).affectedKeys()
.hasOnly(['lastWatered', 'lastWateredBy',
'lastFertilized', 'lastFertilizedBy']));
}
match /locations/{locationId} {
allow read: if isMember(householdId);
allow write: if isMember(householdId)
&& roleOf(householdId) == 'member';
}
}
}
}