From c878a9be1f0b782d3e52c8dc3b1d3b29bd263a13 Mon Sep 17 00:00:00 2001 From: null Date: Fri, 19 Jun 2026 18:46:25 -0500 Subject: [PATCH] =?UTF-8?q?feat:=20Firebase=20project=20config=20=E2=80=94?= =?UTF-8?q?=20Firestore,=20Storage=20rules,=20Functions=20setup=20(batch?= =?UTF-8?q?=20v0.2.3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - .firebaserc: default project set to couples-connect-dev - firebase.json: Firestore rules/indexes, Storage rules, Functions source config - storage.rules: profile photo write/read rules (5MB cap, image-only, owner-scoped) - firestore.indexes.json: empty (no custom indexes yet) --- .firebaserc | 5 +++++ firebase.json | 21 +++++++++++++++++++++ firestore.indexes.json | 4 ++++ storage.rules | 28 ++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+) create mode 100644 .firebaserc create mode 100644 firebase.json create mode 100644 firestore.indexes.json create mode 100644 storage.rules diff --git a/.firebaserc b/.firebaserc new file mode 100644 index 00000000..1c341ef5 --- /dev/null +++ b/.firebaserc @@ -0,0 +1,5 @@ +{ + "projects": { + "default": "couples-connect-dev" + } +} diff --git a/firebase.json b/firebase.json new file mode 100644 index 00000000..4dd6483f --- /dev/null +++ b/firebase.json @@ -0,0 +1,21 @@ +{ + "firestore": { + "rules": "firestore.rules", + "indexes": "firestore.indexes.json" + }, + "storage": { + "rules": "storage.rules" + }, + "functions": [ + { + "source": "functions", + "codebase": "default", + "ignore": [ + "node_modules", + ".git", + "firebase-debug.log", + "firebase-debug.*.log" + ] + } + ] +} diff --git a/firestore.indexes.json b/firestore.indexes.json new file mode 100644 index 00000000..415027e5 --- /dev/null +++ b/firestore.indexes.json @@ -0,0 +1,4 @@ +{ + "indexes": [], + "fieldOverrides": [] +} diff --git a/storage.rules b/storage.rules new file mode 100644 index 00000000..0d24e27f --- /dev/null +++ b/storage.rules @@ -0,0 +1,28 @@ +rules_version = '2'; +service firebase.storage { + match /b/{bucket}/o { + + // Profile photos: only the owner may write; both the owner and their + // partner can read via the tokenized download URL. Direct read is + // scoped to the owner so raw storage paths aren't publicly accessible. + // + // Size cap: 5 MB. Content-type must be an image (enforced at upload, + // not at read, so the header check only blocks mismatched writes). + match /users/{uid}/profile.jpg { + allow write: if request.auth != null + && request.auth.uid == uid + && request.resource.size < 5 * 1024 * 1024 + && request.resource.contentType.matches('image/.*'); + + // Partners receive the tokenized download URL (generated server-side or + // at upload time) which bypasses these rules. Direct rule-based read is + // scoped to the owner only. + allow read: if request.auth != null && request.auth.uid == uid; + } + + // Deny all other paths by default. + match /{allPaths=**} { + allow read, write: if false; + } + } +}