Back to Skills

moai-platform-firestore

modu-ai
Updated Today
185 views
424
78
424
View on GitHub
Otherfirestorefirebasenosqlrealtimeofflinemobile

About

This Claude Skill provides Firebase Firestore expertise for implementing NoSQL patterns, real-time sync, and offline caching in mobile-first apps. Use it when configuring Security Rules, setting up real-time listeners, or building offline-supported applications. It covers Firestore's core capabilities including document modeling and mobile-optimized SDKs.

Quick Install

Claude Code

Recommended
Primary
npx skills add modu-ai/moai-adk
Plugin CommandAlternative
/plugin add https://github.com/modu-ai/moai-adk
Git CloneAlternative
git clone https://github.com/modu-ai/moai-adk.git ~/.claude/skills/moai-platform-firestore

Copy and paste this command in Claude Code to install this skill

Documentation

moai-platform-firestore: Firebase Firestore Specialist

Quick Reference (30 seconds)

Firebase Firestore Expertise: NoSQL document database with real-time synchronization, offline-first architecture, Security Rules, Cloud Functions triggers, and mobile-optimized SDKs.

Core Capabilities

Real-time Sync: Automatic synchronization across all connected clients Offline Caching: IndexedDB persistence with automatic sync when online Security Rules: Declarative field-level access control Cloud Functions: Document triggers for server-side processing Composite Indexes: Complex query optimization

When to Use Firestore

  • Mobile-first applications with offline support
  • Real-time collaborative features
  • Cross-platform apps (iOS, Android, Web, Flutter)
  • Projects requiring Google Cloud integration
  • Apps with flexible, evolving data structures

Context7 Library Access

docs = await mcp__context7__get_library_docs(
    context7CompatibleLibraryID="/firebase/firebase-docs",
    topic="firestore security-rules offline-persistence cloud-functions indexes",
    tokens=6000
)

Implementation Guide

Firestore Initialization with Offline Persistence

import { initializeApp } from 'firebase/app'
import {
  initializeFirestore,
  persistentLocalCache,
  persistentMultipleTabManager,
  CACHE_SIZE_UNLIMITED
} from 'firebase/firestore'

const app = initializeApp({
  apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID
})

export const db = initializeFirestore(app, {
  localCache: persistentLocalCache({
    tabManager: persistentMultipleTabManager(),
    cacheSizeBytes: CACHE_SIZE_UNLIMITED
  })
})

Real-time Listeners with Metadata

import { collection, query, where, orderBy, onSnapshot } from 'firebase/firestore'

export function subscribeToDocuments(userId: string, callback: (docs: any[]) => void) {
  const q = query(
    collection(db, 'documents'),
    where('collaborators', 'array-contains', userId),
    orderBy('createdAt', 'desc')
  )

  return onSnapshot(q, { includeMetadataChanges: true }, (snapshot) => {
    callback(snapshot.docs.map((doc) => ({
      id: doc.id,
      ...doc.data(),
      _pending: doc.metadata.hasPendingWrites,
      _fromCache: doc.metadata.fromCache
    })))
  })
}

Security Rules

Basic Structure:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read, write: if request.auth.uid == userId;
    }

    match /documents/{docId} {
      allow read: if resource.data.isPublic == true
        || request.auth.uid == resource.data.ownerId
        || request.auth.uid in resource.data.collaborators;
      allow create: if request.auth != null
        && request.resource.data.ownerId == request.auth.uid;
      allow update, delete: if request.auth.uid == resource.data.ownerId;
    }
  }
}

Role-Based Access with Custom Claims:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    function isSignedIn() { return request.auth != null; }
    function isAdmin() { return request.auth.token.admin == true; }

    match /organizations/{orgId} {
      function isMember() {
        return exists(/databases/$(database)/documents/organizations/$(orgId)/members/$(request.auth.uid));
      }
      function getMemberRole() {
        return get(/databases/$(database)/documents/organizations/$(orgId)/members/$(request.auth.uid)).data.role;
      }
      function isOrgAdmin() { return isMember() && getMemberRole() in ['admin', 'owner']; }

      allow read: if isSignedIn() && isMember();
      allow update: if isOrgAdmin();
      allow delete: if getMemberRole() == 'owner';

      match /members/{memberId} {
        allow read: if isMember();
        allow write: if isOrgAdmin();
      }

      match /projects/{projectId} {
        allow read: if isMember();
        allow create: if isMember() && getMemberRole() in ['admin', 'owner', 'editor'];
        allow update, delete: if isOrgAdmin() || resource.data.createdBy == request.auth.uid;
      }
    }
  }
}

Composite Indexes Configuration

{
  "indexes": [
    {
      "collectionGroup": "documents",
      "queryScope": "COLLECTION",
      "fields": [
        { "fieldPath": "organizationId", "order": "ASCENDING" },
        { "fieldPath": "createdAt", "order": "DESCENDING" }
      ]
    },
    {
      "collectionGroup": "documents",
      "queryScope": "COLLECTION",
      "fields": [
        { "fieldPath": "tags", "arrayConfig": "CONTAINS" },
        { "fieldPath": "createdAt", "order": "DESCENDING" }
      ]
    }
  ]
}

Cloud Functions V2 Triggers

import { onDocumentUpdated } from 'firebase-functions/v2/firestore'
import { onCall, HttpsError } from 'firebase-functions/v2/https'
import { onSchedule } from 'firebase-functions/v2/scheduler'
import { getFirestore, FieldValue } from 'firebase-admin/firestore'

const db = getFirestore()

export const onDocumentUpdate = onDocumentUpdated(
  { document: 'documents/{docId}', region: 'us-central1' },
  async (event) => {
    const before = event.data?.before.data()
    const after = event.data?.after.data()
    if (!before || !after) return

    const batch = db.batch()
    batch.set(db.collection('changes').doc(), {
      documentId: event.params.docId,
      before, after,
      changedAt: FieldValue.serverTimestamp()
    })
    batch.update(db.doc('stats/documents'), {
      totalModifications: FieldValue.increment(1)
    })
    await batch.commit()
  }
)

export const inviteToOrganization = onCall({ region: 'us-central1' }, async (request) => {
  if (!request.auth) throw new HttpsError('unauthenticated', 'Must be signed in')

  const { organizationId, email, role } = request.data
  const memberDoc = await db.doc(`organizations/${organizationId}/members/${request.auth.uid}`).get()

  if (!memberDoc.exists || !['admin', 'owner'].includes(memberDoc.data()?.role)) {
    throw new HttpsError('permission-denied', 'Must be organization admin')
  }

  const invitation = await db.collection('invitations').add({
    organizationId, email, role,
    invitedBy: request.auth.uid,
    createdAt: FieldValue.serverTimestamp(),
    status: 'pending'
  })

  return { invitationId: invitation.id }
})

export const dailyCleanup = onSchedule(
  { schedule: '0 0 * * *', timeZone: 'UTC', region: 'us-central1' },
  async () => {
    const thirtyDaysAgo = new Date()
    thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30)

    const oldDocs = await db.collection('tempFiles')
      .where('createdAt', '<', thirtyDaysAgo).limit(500).get()

    const batch = db.batch()
    oldDocs.docs.forEach((doc) => batch.delete(doc.ref))
    await batch.commit()
  }
)

Advanced Patterns

Offline-First React Hook

import { useEffect, useState } from 'react'
import { collection, query, where, orderBy, onSnapshot, addDoc, updateDoc, doc, serverTimestamp } from 'firebase/firestore'

export function useTasks(userId: string) {
  const [tasks, setTasks] = useState<any[]>([])
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    if (!userId) return
    const q = query(collection(db, 'tasks'), where('userId', '==', userId), orderBy('createdAt', 'desc'))

    return onSnapshot(q, { includeMetadataChanges: true }, (snapshot) => {
      setTasks(snapshot.docs.map((doc) => ({
        id: doc.id, ...doc.data(),
        _pending: doc.metadata.hasPendingWrites,
        _fromCache: doc.metadata.fromCache
      })))
      setLoading(false)
    })
  }, [userId])

  const addTask = (title: string) => addDoc(collection(db, 'tasks'), {
    title, completed: false, userId, createdAt: serverTimestamp()
  })

  const toggleTask = (taskId: string, completed: boolean) =>
    updateDoc(doc(db, 'tasks', taskId), { completed, updatedAt: serverTimestamp() })

  return { tasks, loading, addTask, toggleTask }
}

Batch Operations and Transactions

import { writeBatch, runTransaction, doc, increment } from 'firebase/firestore'

async function batchUpdate(updates: Array<{ id: string; data: any }>) {
  const batch = writeBatch(db)
  updates.forEach(({ id, data }) => {
    batch.update(doc(db, 'documents', id), { ...data, updatedAt: serverTimestamp() })
  })
  await batch.commit()
}

async function transferCredits(fromUserId: string, toUserId: string, amount: number) {
  await runTransaction(db, async (transaction) => {
    const fromRef = doc(db, 'users', fromUserId)
    const toRef = doc(db, 'users', toUserId)
    const fromDoc = await transaction.get(fromRef)

    if (!fromDoc.exists()) throw new Error('Sender not found')
    if (fromDoc.data().credits < amount) throw new Error('Insufficient credits')

    transaction.update(fromRef, { credits: increment(-amount) })
    transaction.update(toRef, { credits: increment(amount) })
  })
}

Performance and Pricing

Performance Characteristics

Read Latency: 50-200ms (varies by region) Write Latency: 100-300ms Real-time Propagation: 100-500ms Offline Sync: Automatic on reconnection

Free Tier (2024)

Storage: 1GB Daily Reads: 50,000 Daily Writes: 20,000 Daily Deletes: 20,000


Works Well With

  • moai-platform-firebase-auth - Firebase Authentication integration
  • moai-lang-flutter - Flutter SDK patterns
  • moai-lang-typescript - TypeScript client patterns
  • moai-domain-mobile - Mobile architecture patterns
  • moai-quality-security - Security Rules best practices

Status: Production Ready Generated with: MoAI-ADK Skill Factory v2.0 Last Updated: 2025-12-07 Platform: Firebase Firestore

GitHub Repository

modu-ai/moai-adk
Path: .claude/skills/moai-platform-firestore
agentic-aiagentic-codingagentic-workflowclaudeclaudecodevibe-coding

Related Skills

mobile-testing

Other

This Claude Skill provides comprehensive mobile testing for iOS and Android applications, covering gestures, sensors, permissions, and device fragmentation. Use it when testing native, hybrid, or mobile web apps to ensure quality across 1000+ device variants. It helps define device coverage matrices and test key platform differences.

View skill

moai-domain-mobile-app

Testing

This Claude Skill provides enterprise mobile development expertise for React Native 0.76+, Flutter 3.24+, and Capacitor 6.x cross-platform frameworks. It focuses on implementing robust patterns, comprehensive testing, and CI/CD automation for production-ready mobile applications. Use this skill for guidance on mobile architecture, performance optimization, and deployment strategies.

View skill

moai-domain-mobile-app

Testing

This Claude Skill provides enterprise mobile development expertise for React Native 0.76+, Flutter 3.24+, and Capacitor 6.x frameworks. It focuses on cross-platform patterns, testing strategies, and CI/CD automation for production-ready applications. Use this skill for guidance on modern mobile development workflows and deployment best practices.

View skill

moai-lang-flutter

Other

This Claude Skill specializes in Flutter 3.24+ and Dart 3.5+ development, focusing on modern state management with Riverpod and declarative navigation using go_router. It is designed for building cross-platform mobile, desktop, and web applications. Use this skill for guidance on adaptive layouts, Dart's latest language features, and integrating platform-specific functionality.

View skill