Claude Code Plugins

Community-maintained marketplace

Feedback

moai-platform-firestore

@modu-ai/moai-adk
391
0

Firebase Firestore specialist covering NoSQL patterns, real-time sync, offline caching, and Security Rules. Use when building mobile-first apps with offline support, implementing real-time listeners, or configuring Firestore security.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name moai-platform-firestore
description Firebase Firestore specialist covering NoSQL patterns, real-time sync, offline caching, and Security Rules. Use when building mobile-first apps with offline support, implementing real-time listeners, or configuring Firestore security.
version 1.0.0
category platform
updated Sun Dec 07 2025 00:00:00 GMT+0000 (Coordinated Universal Time)
status active
tags firestore, firebase, nosql, realtime, offline, mobile
context7-libraries /firebase/firebase-docs
related-skills moai-platform-firebase-auth, moai-lang-flutter, moai-lang-typescript
allowed-tools Read, Write, Bash, Grep, Glob

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