# Scalability - Firebase Implementation

Firebase-specific implementation of the principles defined in [SCALABILITY_CORE.md](../core/SCALABILITY_CORE.md).

## Statelessness

- **Cloud Functions Are Stateless:** Cloud Functions instances are ephemeral and may be recycled at any time. Never store request-scoped state in global variables expecting it to persist across invocations. Use Firestore, RTDB, or Memorystore for shared state.
- **Global Scope for Reusable Connections:** While function instances are stateless per-request, global scope persists across invocations of the same instance. Initialize expensive resources (Firestore client, HTTP clients, Admin SDK) in global scope to reuse connections across warm invocations. Do not store per-request data there.
- **Session State in Firestore:** Store user session data (cart, wizard progress, form drafts) in Firestore documents keyed by user ID. Never rely on client-side memory for critical flow state -- the user may switch devices or the app may be killed.
- **Idempotent Operations:** Design all Cloud Functions (especially those triggered by Firestore, Pub/Sub, or Eventarc) to be idempotent. Firebase may deliver events more than once. Use event IDs or transaction checks to prevent duplicate processing.

## Decoupling (Async First)

- **Firestore Triggers for Background Work:** Move time-consuming operations (sending emails, generating thumbnails, syncing to external systems) into Firestore-triggered Cloud Functions (`onDocumentCreated`, `onDocumentUpdated`). The client writes a document; the backend reacts asynchronously.
- **Pub/Sub for Fan-Out:** When a single event must trigger multiple independent actions (analytics, notifications, cache invalidation), publish to a Pub/Sub topic and let separate Cloud Functions subscribe. This decouples producers from consumers and allows independent scaling.
- **Task Queues for Controlled Processing:** Use Cloud Tasks with Cloud Functions for work that needs controlled retry, rate limiting, or delayed execution. Configure max retry attempts, backoff, and rate limits per queue. Ideal for webhooks, batch processing, and external API calls.
- **Event-Driven Architecture with Eventarc:** Use Eventarc to route events from Firebase services (Auth user creation, Storage uploads) and Google Cloud services to Cloud Functions. This provides a unified event routing layer with delivery guarantees and dead-letter handling.
- **Scheduled Functions:** Use `onSchedule` Cloud Functions for recurring tasks (data aggregation, cleanup, report generation). Define the schedule using cron syntax. Ensure the function completes within the timeout and handles overlapping executions gracefully.

## Database Scaling

- **Firestore Data Modeling for Scale:** Design Firestore schemas around your query patterns, not normalized relational models. Denormalize data that is read together. Use subcollections to scope queries and distribute writes. A single document should never be written more than once per second.
- **Avoid Hotspots:** Firestore distributes data across storage servers by document ID. Sequential IDs (timestamps, auto-incrementing counters) cause write hotspots. Use Firestore auto-generated IDs or add randomness to custom IDs for write-heavy collections.
- **Collection Group Queries:** Use collection group queries to search across all subcollections with the same name. This enables patterns like "find all comments across all posts by user X" without denormalization. Create the required composite indexes.
- **Aggregation Strategies:** Firestore does not natively support `COUNT`, `SUM`, or `AVG` at scale (count aggregation exists but has limits). Maintain running aggregations in dedicated counter documents updated by Cloud Functions using `FieldValue.increment()`. Use distributed counters for high-write scenarios.
- **RTDB for Real-Time Presence:** Use Firebase Realtime Database (not Firestore) for presence systems and high-frequency, low-latency updates (typing indicators, cursor positions). RTDB's `onDisconnect` handler enables reliable offline detection that Firestore cannot match.
- **Sharding Large Collections:** For collections expecting millions of documents with high write throughput, implement document-level or field-level sharding. Split counters across N shards (`counter_0`, `counter_1`, ...) and sum them on read.
- **Composite Indexes:** Create composite indexes proactively for all multi-field queries. Monitor the Firebase console for index creation suggestions. Missing indexes cause query failures at runtime -- catch them in testing, not production.

## Graceful Degradation

- **Firestore Offline Persistence:** Enable Firestore offline persistence on the client. The SDK caches documents locally and serves reads from cache when offline. Writes are queued and synced when connectivity is restored. Design the UX to indicate offline state without blocking the user.
- **Circuit Breakers for External Calls:** Cloud Functions that call external APIs (payment gateways, email providers) must implement circuit breakers. After N consecutive failures, stop calling the external service and fall back to a queued retry via Cloud Tasks or Pub/Sub.
- **Feature Degradation with Remote Config:** Use Firebase Remote Config to toggle features and degrade gracefully. If a dependent microservice is down, disable the feature in Remote Config rather than showing errors. Define fallback values for every Remote Config parameter.
- **Timeout Configuration:** Set appropriate timeouts for Cloud Functions (`timeoutSeconds`) based on the work performed. For HTTP-triggered functions, set client-side timeouts that are shorter than the function timeout. For Firestore triggers, ensure processing completes well within the maximum timeout (540 seconds for v2 functions).

## API Versioning & Compatibility

- **Callable Function Versioning:** Version callable Cloud Functions by name (`submitOrderV1`, `submitOrderV2`) or by including a version field in the request payload. Support the previous version during migration windows. Remove deprecated versions only after client adoption metrics confirm no usage.
- **Firestore Schema Evolution:** Evolve Firestore document schemas by adding optional fields with default values. Never rename or remove fields that active clients depend on. Use Cloud Functions to backfill new fields on existing documents during migrations.
- **Backward-Compatible Triggers:** When modifying Firestore trigger functions, ensure they handle both old and new document schemas. A trigger processing `onDocumentUpdated` will encounter documents written by both old and new client versions during rollout.
- **Remote Config for Feature Flags:** Use Firebase Remote Config to gate new features behind flags. Release the backend (Cloud Functions, Security Rules) first, then enable the feature for clients via Remote Config. This decouples backend deployment from client rollout.
- **Minimum App Version Enforcement:** Store the minimum supported app version in Remote Config or a Firestore document. Check on app startup and force users on outdated versions to update before continuing. This allows deprecating old API contracts safely.
