Skip to content

Conversation

@joehan
Copy link
Member

@joehan joehan commented Jan 8, 2026

Slightly more polished draft of the firestore-basics skill. It covers:

  • Provisioning a DB and setting up your firebase.json, rules, and index filkes
  • Setting up SDKs on each platform, and a bunch of usage examples
  • A bunch of usage examples of security rules common patterns

TODOs

  • Add compatibility field that tells agents to instal the CLI if possible
  • Add more in depth examples to security rules
  • Add deployment section to provisioning.md
  • Test and iterate - can we reduce token usage by putting the most basic CUJs directly in SKILL.md?

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @joehan, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces the initial draft of a new 'firestore-basics' skill. Its primary goal is to serve as a comprehensive resource for users looking to understand and implement Cloud Firestore, covering essential aspects from initial setup and configuration to securing data with rules and integrating the SDK into applications.

Highlights

  • New Firestore Basics Skill: Introduced a new skill named firestore-basics which serves as a comprehensive guide for Cloud Firestore.
  • Provisioning Guide: Added detailed documentation for setting up Cloud Firestore, covering Firebase CLI initialization, firebase.json configuration, and local emulator usage.
  • Security Rules Documentation: Provided explanations for Firestore Security Rules, including basic structure, common patterns (locked, test, auth required, user-specific), and deployment instructions.
  • SDK Usage Examples: Included guidance and code snippets for initializing and using the Firestore Web Modular SDK, connecting to the emulator, and performing basic data operations like adding, reading, and listening for real-time updates.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new 'firestore-basics' skill, providing a foundational guide to Cloud Firestore. The skill is well-structured into provisioning, security rules, and SDK usage. My review includes suggestions to enhance the examples and documentation to make them more practical for users. Specifically, I've recommended improving how data is logged in the SDK examples, adding more advanced security rule patterns like data validation and separated read/write access, and including a section on deploying Firestore configurations. These suggestions align with the TODOs mentioned in the pull request description and aim to make the skill more complete.

@joehan joehan marked this pull request as ready for review January 9, 2026 17:30
@joehan
Copy link
Member Author

joehan commented Jan 9, 2026

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new 'firestore-basics' skill, providing comprehensive documentation and code examples for web, Android, and iOS. The content is well-structured and covers key aspects of Firestore, including provisioning, security rules, SDK usage, and indexes. My review focuses on improving the correctness and clarity of the code snippets and documentation. I've identified several issues, such as incorrect API usage in the Android SDK examples, unsafe coding practices like force-unwrapping in Swift, and formatting problems in the markdown files. I've provided specific suggestions to fix these issues, which will enhance the quality and reliability of the skill for developers.


```kotlin
db.collection("cities")
.orderBy("name", Query.Direction.KEY_ASCENDING)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Query.Direction.KEY_ASCENDING is not a valid enum member and will cause a compilation error. The correct values are Query.Direction.ASCENDING and Query.Direction.DESCENDING.

Suggested change
.orderBy("name", Query.Direction.KEY_ASCENDING)
.orderBy("name", Query.Direction.ASCENDING)

Comment on lines 67 to 76
```
match /databases/{database}/documents {
// Allow access based on email domain
match /some_collection/{document} {
allow read: if request.auth != null
&& request.auth.email_verified
&& request.auth.email.endsWith('@example.com')
}
}
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The example for allowing access to users with verified emails contains a redundant and incorrect nested match /databases/{database}/documents block. Security rules files should only have one top-level service block, and match blocks for paths are nested within that. This extra nesting will cause a syntax error.

Suggested change
```
match /databases/{database}/documents {
// Allow access based on email domain
match /some_collection/{document} {
allow read: if request.auth != null
&& request.auth.email_verified
&& request.auth.email.endsWith('@example.com')
}
}
```
### Allow only verified emails
Requires users to verify ownership of the email address before using it to read or write data. This snippet should be placed inside your `match /databases/{database}/documents` block.
```firestore
// Allow access based on email domain
match /some_collection/{document} {
allow read: if request.auth != null
&& request.auth.email_verified
&& request.auth.email.endsWith('@example.com');
}

Comment on lines 7 to 17
import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore";

const firebaseConfig = {
// Your config options. Get the values by running 'firebase apps:sdkconfig <platform> <app-id>'
};

const app = initializeApp(firebaseConfig);
const db = getFirestore(app);

```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The markdown formatting in this section is broken. The import statements are outside the code block, and there is a stray ``` at the end. This makes the example incorrect and hard to read. All code, including imports, should be inside a single javascript code block. Additionally, this guide is missing an example for connecting to the Firestore emulator, which is present in the Android and iOS guides. This formatting issue is repeated for all code examples in this file.

Suggested change
import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore";
const firebaseConfig = {
// Your config options. Get the values by running 'firebase apps:sdkconfig <platform> <app-id>'
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
```
import { initializeApp } from "firebase/app";
import { getFirestore, connectFirestoreEmulator } from "firebase/firestore";
const firebaseConfig = {
// Your config options. Get the values by running 'firebase apps:sdkconfig <platform> <app-id>'
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
// Connect to Emulator. This should be conditional (e.g. in a development environment).
connectFirestoreEmulator(db, 'localhost', 8080);


// Merge
db.collection("cities").document("LA")
.set(mapOf("population" to 3900000), SetOptions.merge())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The SetOptions.merge() call will fail without the required import. Please add import com.google.firebase.firestore.SetOptions to the imports section at the top of the file to make this code snippet runnable.

val snapshot = transaction.get(sfDocRef)

// Note: You can also use FieldValue.increment() for simple counters
val newPopulation = snapshot.getDouble("population")!! + 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using the not-null assertion operator (!!) is risky as it can cause a NullPointerException if the "population" field is missing or not a Double, which would crash the app. It's safer to handle this potential null case gracefully, for example by using the elvis operator ?: with a default value.

Suggested change
val newPopulation = snapshot.getDouble("population")!! + 1
val newPopulation = (snapshot.getDouble("population") ?: 0.0) + 1

if let err = err {
print("Error adding document: \(err)")
} else {
print("Document added with ID: \(ref!.documentID)")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Force-unwrapping ref! with ! can lead to a runtime crash if ref is nil for any reason. It's safer to use optional chaining ? or optional binding if let.

Suggested change
print("Document added with ID: \(ref!.documentID)")
print("Document added with ID: \(ref?.documentID ?? "N/A")")

Comment on lines +129 to +130
let dataDescription = document.data().map(String.init(describing:)) ?? "nil"
print("Document data: \(dataDescription)")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using String(describing:) on the document.data() dictionary is not very illustrative for developers. It would be more helpful to show an example of how to access individual fields from the data dictionary, for instance, by casting a value to its expected type.

Example:

if let data = document.data() {
    let name = data["name"] as? String ?? "N/A"
    print("City name: \(name)")
}

if let err = err {
print("Error getting documents: \(err)")
} else {
for document in querySnapshot!.documents {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Force-unwrapping querySnapshot! is unsafe. If an error occurs that is not caught by if let err = err, but querySnapshot is still nil, this will cause a crash. It's safer to use optional binding or the nil-coalescing operator.

Suggested change
for document in querySnapshot!.documents {
for document in querySnapshot?.documents ?? [] {

Comment on lines 81 to 93
## Deploy rules and indexes
To deploy all rules and indexes
```
firebase deploy --only firestore
```
To deploy just rules
```
firebase deploy --only firestore:rules
```
To deploy just indexes
```
firebase deploy --only firestore:indexes
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The deployment commands are currently formatted as separate lines of inline code, which is hard to read and copy. It would be better to group them into a single bash code block for clarity and ease of use.

Suggested change
## Deploy rules and indexes
To deploy all rules and indexes
```
firebase deploy --only firestore
```
To deploy just rules
```
firebase deploy --only firestore:rules
```
To deploy just indexes
```
firebase deploy --only firestore:indexes
```
## Deploy rules and indexes
To deploy all rules and indexes:
```bash
firebase deploy --only firestore

To deploy just rules:

firebase deploy --only firestore:rules

To deploy just indexes:

firebase deploy --only firestore:indexes

await runTransaction(db, async (transaction) => {
const sfDoc = await transaction.get(sfDocRef);
if (!sfDoc.exists()) {
throw "Document does not exist!";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

It's better practice to throw Error objects instead of string literals. Error objects capture stack traces and can be more easily distinguished from other thrown values, which improves debugging.

Suggested change
throw "Document does not exist!";
throw new Error("Document does not exist!");

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant