Skip to main content

Data, Storage & Async

Paved Path

  • Datastore: Firestore (Native mode)
  • Files: Firebase Storage (GCS)
  • Cache: none initially
  • Search: Algolia (nearโ€‘realโ€‘time sync)
  • Async jobs: Cloud Tasks
  • Eventing: Pub/Sub
  • Backups: Daily Firestore exports; 30โ€‘day retention
  • PII governance: Lean (tag collections, leastโ€‘privilege IAM, default encryption)
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import algoliasearch from 'algoliasearch';

admin.initializeApp();
const client = algoliasearch(process.env.ALGOLIA_APP_ID!, process.env.ALGOLIA_API_KEY!);
const index = client.initIndex('users');

export const onUserWrite = functions.firestore
.document('users/{id}')
.onWrite(async (change, context) => {
const id = context.params.id;
if (!change.after.exists) return index.deleteObject(id);
const data = change.after.data()!;
await index.saveObject({ objectID: id, ...data });
});
import { CloudTasksClient } from '@google-cloud/tasks';
const client = new CloudTasksClient();
export async function enqueue(url: string, payload: any) {
const [res] = await client.createTask({
parent: client.queuePath('proj', 'loc', 'queue'),
task: { httpRequest: { httpMethod: 'POST', url, body: Buffer.from(JSON.stringify(payload)).toString('base64') } }
});
return res.name;
}

LLM Notes

  • When modeling Firestore, optimize for access patterns. Prefer flat collections with indexes over deep nesting.