Work / Chitragupt / Wiki / Decisions
2026-06-28-disputes-evidence-storage-scope
Decisioncanonicalverified 2026-06-28
DECISION.2026-06-28.DISPUTES-EVIDENCE-STORAGE-SCOPEdisputes/{disputeId}/evidence storage rule scoped to dispute participants
Decision
firebase/storage.rules for disputes/{disputeId}/evidence/{allPaths=**} now gates both read and write on dispute participation, derived via a firestore.get() of disputes/{disputeId} and a comparison against request.auth.uid matching either client_uid or ca_uid. Admins still get unconditional read + write (write also requires verified email + image-or-PDF + size cap, unchanged).
The previous rule allowed any signed-in user to upload to disputes/{disputeId}/evidence/*, deferring the participant check to the callable that issued the upload URL. That broke the principle that storage rules are the actual gate, since a leaked dispute id was enough for a third party to attach evidence.
Why
Phase 7a exit criterion (.context/features/index.md §7a) requires the storage rule itself to be scoped, not the callable that wraps it. The cost is one extra firestore.get() per upload — acceptable because dispute evidence uploads are rare and the dispute doc is the same one the participant's UI is already subscribed to.
Impact
firebase/storage.rules— newdisputeParticipant(disputeId)helper;match /disputes/{disputeId}/evidence/{allPaths=**}gates read + write onisAdmin() || disputeParticipant(disputeId).- No callable-side change required; the new wiring is strictly tighter than the old behaviour.
- Existing dispute participants (client + CA on the dispute) keep their upload flow unchanged.
Status
Active.
Sources
- .context/features/index.md — Phase 7a exit criterion
firebase/firestore.rules—disputes/{disputeId}participant rule (mirror of the storage check)
Every project of mine is written down like this.
Read the résumé