Personal Catalogue: React & Firebase — Chapter 5, Exercise 3 ===================================================================== TASK Call addTag() against a real Cd's or Dvd's own document ID both before and after deploying the tagsOnlyOnBooks rule, and explain precisely why the outcome differs — including why neither of the two earlier rule functions from Chapter 3 already caught this. SOLUTION Before deploying tagsOnlyOnBooks: await addTag(realCdDocumentId, "Anything"); // Succeeds, no error. The Cd document now has tags: ['Anything']. After adding tagsOnlyOnBooks() to firestore.rules and running `firebase deploy --only firestore:rules`: await addTag(realCdDocumentId, "Anything"); // FirebaseError: Missing or insufficient permissions. Why the outcome differs: before the new rule existed, nothing in firestore.rules ever inspected whether a tags field belonged on the document receiving it — the write only had to satisfy the three existing checks, and it satisfied all three. After the new rule exists, the same write is checked against a fourth condition, tagsOnlyOnBooks(), which evaluates the resulting document (itemType: 'Cd', now carrying a tags field) and finds itemType isn't 'Book', so the rule returns false and the whole write is rejected. Why neither earlier rule function caught this: - hasValidBaseFields() only checks that title is a non-empty string and itemType is one of the four valid values — both are still true for this Cd document even with a stray tags field added. - hasTypeRequiredFields() only checks that each type's own required field (author for Book, artist for Cd) is present — the Cd's real artist field was never touched by this write, so this check still passes too. Neither function was ever designed to reject an unexpected field being present — both only confirm that expected fields are present. That's exactly the same category of gap Chapter 4 described for a leftover author field surviving on a Cd document: checking for what's required is a genuinely different check from forbidding what isn't allowed, and this project's rules only did the first kind until this chapter added the second. WHY THIS WORKS AS AN ANSWER ---------------------------- It shows the real before/after outcome of the same exact call, and walks through both pre-existing rule functions individually to explain precisely why each one still returns true even with the stray field present, rather than a vague "the rules didn't check for that."