Skip to content

Commit 2cb4c15

Browse files
committed
feat(docs): add initial developer documentation
This commit introduces a new developer documentation hub under the `devdocs` directory. The goal of this new documentation is to provide a comprehensive resource for developers working on the Firestore JS SDK. The new documentation includes: - **Overview:** A high-level overview of the SDK, its goals, and architecture. - **Prerequisites:** A guide for new contributors, outlining the necessary skills and knowledge. - **Architecture:** A detailed explanation of the SDK's architecture, core components, and data flow. - **Code Layout:** A document that explains the structure of the codebase. - **Build & Testing:** Initial documents for the build and testing processes.
1 parent 4d834de commit 2cb4c15

File tree

8 files changed

+209
-0
lines changed

8 files changed

+209
-0
lines changed

packages/firestore/GEMINI.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Firestore JavaScript SDK
2+
This project is the official JavaScript SDK for the [Google Cloud Firestore](https://firebase.google.com/docs/firestore) database.
3+
4+
You are an expert in @devdocs/prerequisites.md
5+
@devdocs/overview.md
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# SDK Architecture
2+
3+
This document provides a detailed explanation of the Firestore JavaScript SDK's architecture, its core components, and the flow of data through the system.
4+
5+
## Core Components
6+
7+
The SDK is composed of several key components that work together to provide the full range of Firestore features.
8+
9+
![Architecture Diagram](./architecture.png)
10+
11+
* **API Layer**: The public-facing API surface that developers use to interact with the SDK. This layer is responsible for translating the public API calls into the internal data models and passing them to the appropriate core components.
12+
* **Core**:
13+
* **Event Manager**: Acts as a central hub for all eventing in the SDK. It is responsible for routing events between the API Layer and Sync Engine. It manages query listeners and is responsible for raising snapshot events, as well as handling connectivity changes and some query failures.
14+
* **Sync Engine**: The central controller of the SDK. It acts as the glue between the Event Manager, Local Store, and Remote Store. Its responsibilities include:
15+
* Coordinating client requests and remote events.
16+
* Managing a view for each query, which represents the unified view between the local and remote data stores.
17+
* Notifying the Remote Store when the Local Store has new mutations that need to be sent to the backend.
18+
* **Local Store**: A container for the components that manage persisted and in-memory data.
19+
* **Remote Table**: A cache of the most recent version of documents as known by the Firestore backend.
20+
* **Mutation Queue**: A queue of all the user-initiated writes (set, update, delete) that have not yet been acknowledged by the Firestore backend.
21+
* **Local View**: A cache that represents the user's current view of the data, combining the Remote Table with the Mutation Queue.
22+
* **Remote Store**: The component responsible for all network communication with the Firestore backend. It manages the gRPC streams for reading and writing data, and it abstracts away the complexities of the network protocol from the rest of the SDK.
23+
* **Persistence Layer**: The underlying storage mechanism used by the Local Store to persist data on the client. In the browser, this is implemented using IndexedDB.
24+
25+
The architecture and systems within the SDK map closely to the directory structure, which helps developers navigate the codebase. Here is a mapping of the core components to their corresponding directories.
26+
27+
* `src/`:
28+
* `api/`: Implements the **API Layer** for the main SDK.
29+
* `lite-api/`: Implements the **API Layer** for the lite SDK.
30+
* `core/`: Implements the **Sync Engine** and **Event Manager**.
31+
* `local/`: Implements the **Local Store**, which includes the **Mutation Queue**, **Remote Table**, **Local View**, and the **Persistence Layer**.
32+
* `remote/`: Implements the **Remote Store**, handling all network communication.
33+
34+
For a more detailed explanation of the contents of each directory, see the [Code Layout](./code-layout.md) documentation.
35+
36+
## Overview of features
37+
38+
At a high level, all interactions with Firestore can be categorized as either reading or writing data. The SDK provides different mechanisms for these operations, each with distinct guarantees and performance characteristics. There is also a special case of writing data called tansactions detailed below.
39+
40+
41+
### Read Operations
42+
43+
There are two fundamental ways to read data from Firestore:
44+
45+
* **One-Time Reads**: This is for fetching a snapshot of data at a specific moment. It's a simple request-response model. You ask for a document or the results of a query, and the server sends back the data as it exists at that instant.
46+
47+
* **Real-Time Listeners**: This allows you to subscribe to a document or a query. The server first sends you the initial data and then continues to push updates to your client in real time as the data changes. This is the foundation of Firestore's real-time capabilities.
48+
49+
When a query is executed, the SDK immediately returns data from the local cache, which includes any pending optimistic writes from the **Mutation Queue**. This provides a fast, responsive experience. At the same time, the SDK sends the query to the Firestore backend to fetch the latest version of the documents. When the fresh documents arrive from the backend, the SDK takes these server-authoritative documents and re-applies any pending mutations from the local queue on top of them. It then re-runs the original query against this newly merged data. If the documents still match the query's criteria, they are delivered to the query listener again. This is a common occurrence and means a listener could see an event for the same document twice: first with the cached, optimistic data, and a second time after the backend data is reconciled.
50+
51+
### Write Operations
52+
53+
All data modifications—creates, updates, and deletes—are treated as "writes." The SDK is designed to make writes atomic and resilient. There are two fundamental ways to write data to Firestore:
54+
55+
* **One-Time Writes**: When a user performs a write (create, update, or delete), the operation is not sent directly to the backend. Instead, it's treated as a "mutation" and added to the local **Mutation Queue**. The SDK "optimistically" assumes the write will succeed on the backend and immediately reflects the change in the local view of the data, making the change visible to local queries. The SDK then works to synchronize this queue with the backend. This design is crucial for supporting offline functionality, as pending writes can be retried automatically when network connectivity is restored.
56+
57+
* **Transactions**: For grouping multiple write operations into a single atomic unit, the SDK provides `runTransaction`. Unlike standard writes, transactions do not use the optimistic, offline-capable write pipeline. Instead, they are sent directly to the backend, which requires an active internet connection. This ensures atomicity but means transactions do not benefit from the offline capabilities of the standard write pipeline.
58+
59+
60+
# Data Flow
61+
62+
Here's a step-by-step walkthrough of how data flows through the SDK for a write operation, referencing the core components.
63+
64+
## Write Data Flow
65+
66+
1. **API Layer**: A user initiates a write operation (e.g., `setDoc`, `updateDoc`, `deleteDoc`).
67+
2. **Sync Engine**: The call is routed to the Sync Engine, which wraps the operation in a "mutation".
68+
3. **Mutation Queue (in Local Store)**: The Sync Engine adds this mutation to the Mutation Queue. The queue is persisted to the **Persistence Layer** (IndexedDB). At this point, the SDK "optimistically" considers the write successful locally.
69+
4. **Local View (in Local Store)**: The change is immediately reflected in the Local View, making it available to any active listeners without waiting for backend confirmation.
70+
5. **Remote Store**: The Sync Engine notifies the Remote Store that there are pending mutations.
71+
6. **Backend**: The Remote Store sends the mutations from the queue to the Firestore backend.
72+
7. **Acknowledgement**: The backend acknowledges the write.
73+
8. **Mutation Queue (in Local Store)**: The Remote Store informs the Sync Engine, which then removes the acknowledged mutation from the Mutation Queue.
74+
75+
## Read Data Flow (with a Real-Time Listener)
76+
77+
1. **API Layer**: A user attaches a listener to a query (e.g., `onSnapshot`).
78+
2. **Event Manager**: The Event Manager creates a listener and passes it to the Sync Engine.
79+
3. **Sync Engine**: The Sync Engine creates a "view" for the query.
80+
4. **Local View (in Local Store)**: The Sync Engine asks the Local Store for the current documents matching the query. This includes any optimistic local changes from the **Mutation Queue**.
81+
5. **API Layer**: The initial data from the Local View is sent back to the user's `onSnapshot` callback. This provides a fast, initial result.
82+
6. **Remote Store**: Simultaneously, the Sync Engine instructs the Remote Store to listen to the query on the Firestore backend.
83+
7. **Backend**: The backend returns the initial matching documents for the query.
84+
8. **Remote Table (in Local Store)**: The Remote Store receives the documents and saves them to the Remote Table in the Local Store, overwriting any previously cached versions of those documents.
85+
9. **Sync Engine**: The Sync Engine is notified of the updated documents. It re-calculates the query view by combining the new data from the Remote Table with any applicable pending mutations from the **Mutation Queue**.
86+
10. **API Layer**: If the query results have changed after this reconciliation, the new results are sent to the user's `onSnapshot` callback. This is why a listener may fire twice initially.
87+
11. **Real-time Updates**: From now on, any changes on the backend that affect the query are pushed to the Remote Store, which updates the Remote Table, triggering the Sync Engine to re-calculate the view and notify the listener.
119 KB
Loading

packages/firestore/devdocs/build.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Build Process
2+
3+
This document provides a detailed explanation of the Firestore JavaScript SDK build process for the main and lite packages.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# SDK Code Layout
2+
3+
This document explains the code layout in this repository. It is closely related to the [architecture](./architecture.md).
4+
5+
* `src/`: Contains the source code for the main `@firebase/firestore` package.
6+
* `api/`: Implements the **API Layer** for the main SDK.
7+
* `lite-api/`: Contains the entry point of for the lite SDK.
8+
* `core/`: Contains logic for the **Sync Engine** and **Event Manager**.
9+
* `local/`: Contains the logic the **Local Store**, which includes the **Mutation Queue**, **Remote Table**, **Local View**, and the **Persistence Layer**.
10+
* `remote/`: Contains the logic for the **Remote Store**, handling all network communication.
11+
* `model/`: Defines the internal data models used throughout the SDK, such as `Document`, `DocumentKey`, and `Mutation`. These models are used to represent Firestore data and operations in a structured way.
12+
* `platform/`: Contains platform-specific code to abstract away the differences between the Node.js and browser environments. This includes things like networking, storage, and timers. This allows the core logic of the SDK to be platform-agnostic.
13+
* `protos/`: Contains the Protocol Buffer (`.proto`) definitions that describe the gRPC API surface of the Firestore backend. These files are used to generate the client-side networking code.
14+
* `lite/`: Defines the entrypoint code for the `@firebase/firestore/lite` package.
15+
* `test/`: Contains all unit and integration tests for the SDK. The tests are organized by component and feature, and they are essential for ensuring the quality and correctness of the code.
16+
* `scripts/`: Contains a collection of build and maintenance scripts used for tasks such as bundling the code, running tests, and generating documentation.
17+
18+
TODO: Add more detailed information as appropriate on each folder
19+
20+
TODO: Mention critical entry points
21+
- `package.json` for packages and common commands. Go to [build.md](./build.md) for details
22+
- rollup configs for main and lite sdks. Go to [build.md](./build.md) for details
23+
- tests entry points. Go to [testing.md](./testing.md) for details
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Firestore JavaScript SDK Overview
2+
3+
This document is the starting point for navigating the Firestore JavaScript SDK codebase documentation. It provides a high-level overview of the SDK, how it is built, tested, and the developer workflow.
4+
5+
All contributors are expected to be familiar with the [prerequisites](./prerequisites.md) before working in this codebase.
6+
7+
## Project Goals
8+
9+
The Firestore JavaScript SDK is one of the official client-side library for interacting with [Google Cloud Firestore](https://firebase.google.com/docs/firestore). It is designed to be used in a variety of JavaScript environments, including web browsers (primary and common) and Node.js (secondary and rare). It is important to distinguish this SDK from the [Google Cloud Firestore server-side SDK for Node.js](https://github.com/googleapis/nodejs-firestore). While this SDK can run in Node.js, it is primarily designed for client-side use. The server-side SDK is intended for trusted environments and offers different capabilities. However, the two SDKs are designed to harmonize where helpful (e.g. data models) to facilitate easier full-stack application development.
10+
11+
The primary goals of this SDK are:
12+
13+
* Provide a simple and intuitive API for reading and writing data to Firestore.
14+
* Support real-time data synchronization with streaming queries.
15+
* Enable offline data access and query caching.
16+
* Offer a lightweight version for applications that do not require advanced features.
17+
* Maintain API and architectural symmetry with the [Firestore Android SDK](https://github.com/firebase/firebase-android-sdk) and [Firestore iOS SDK](https://github.com/firebase/firebase-ios-sdk). This consistency simplifies maintenance and makes it easier to port features between platforms. The public API is intentionally consistent across platforms, even if it means being less idiomatic, to allow developers to more easily port their application code.
18+
19+
## Artifacts
20+
21+
The Firestore JavaScript SDK is divided into two main packages:
22+
23+
* `@firebase/firestore`: The main, full-featured SDK that provides streaming and offline support.
24+
* `@firebase/firestore/lite`: A much lighter-weight (AKA "lite") version of the SDK for applications that do not require streaming or offline support.
25+
26+
For a detailed explanation of the architecture, components, and data flow, please see the [Architecture documentation](./architecture.md). Related, for a deailed overview of the source code layout, please see [Code layout](./code-layout.md).
27+
28+
29+
## Build
30+
31+
TODO: Add critical information about the build process including optimizations for code size, etc.
32+
33+
For information on how the artifacts are built, please see the [Build documentation](./build.md) file.
34+
35+
## Testing
36+
37+
TODO: Add critical information about the tests harness, organization, spec tests, etc.
38+
39+
For information on how the tests are setup and organized [Testing documentation](./testing.md) file.
40+
41+
## Developer Workflow
42+
43+
TODO: Add list of common commands here.
44+
45+
For information on the developer workflow, including how to build, test, and format the code, please see the [CONTRIBUTING.md](../CONTRIBUTING.md) file.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Firestore JavaScript SDK Maintainer's Guide
2+
3+
This document outlines the prerequisite knowledge for new maintainers of the Firestore JavaScript SDK.
4+
5+
## Prerequisite Knowledge
6+
7+
Before contributing to this codebase, you should have a strong understanding of the following technologies and concepts:
8+
9+
### Core Technologies
10+
11+
* **TypeScript:** The entire codebase is written in TypeScript. A deep understanding of TypeScript, including its type system, generics, and modules, is essential.
12+
* **JavaScript (ES6+):** As a JavaScript SDK, a strong grasp of modern JavaScript features is required.
13+
* **Node.js:** The SDK is isomorphic and runs in the Node.js environment. Familiarity with Node.js concepts, such as its module system and event loop, is important.
14+
* **Browser Runtime Environment:** The SDK is also used in web browsers. A good understanding of the different browser execution contexts (e.g. main window, web/service workers) and subsystems (e.g. persistence like IndexedDB and Local Storage, networking) is necessary.
15+
16+
### Build and Test Tooling
17+
18+
* **Yarn:** We use Yarn for package management. You should be familiar with basic Yarn commands.
19+
* **Rollup.js:** Our build process uses Rollup.js to bundle the code. Understanding Rollup's configuration and plugin system will be helpful.
20+
* **Karma, Mocha, and Chai:** These are our testing frameworks. You should be comfortable writing and running tests using this stack.
21+
22+
23+
24+
### Domain Knowledge
25+
26+
* **[Google Cloud Firestore](https://firebase.google.com/docs/firestore):** A deep understanding of Firestore's data model (documents, collections, subcollections), query language, and security rules is fundamental.
27+
* **Databases:** A general understanding of databases, including key-value stores and relational databases, is helpful for understanding Firestore's design and trade-offs.
28+
* **Modern Web Application Architecture:** Familiarity with modern web application architecture and also server-side rendering (SSR), is beneficial for understanding how the SDK is used in practice.
29+
* **[Firebase](https://firebase.google.com/docs):** Familiarity with the Firebase platform is required, especially Firebase Auth and Firebase Functions.
30+
* **Protocol Buffers / gRPC:** The main SDK uses Protocol Buffers over gRPC to communicate with the Firestore backend. A basic understanding of these technologies is helpful.
31+
* **Firestore REST API:** The lite SDK uses the Firestore REST API. Familiarity with the REST API is useful when working on the lite version of the SDK.

packages/firestore/devdocs/testing.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Build Process
2+
3+
This document provides a detailed explanation of the Firestore JavaScript SDK testing strategy, tech stack, and patterns and practices.
4+
5+
# Tech Stack
6+
- karma, mocha, chai
7+
8+
# Strategy
9+
- Firebase emulator for local development
10+
- Integration testing with the backend
11+
12+
# Patterns and Practices
13+
14+
15+
# Spec Tests

0 commit comments

Comments
 (0)