MCP HubMCP Hub
스킬 목록으로 돌아가기

moai-platform-firestore

modu-ai
업데이트됨 Today
188 조회
424
78
424
GitHub에서 보기
기타firestorefirebasenosqlrealtimeofflinemobile

정보

이 Claude Skill은 모바일 우선 앱에서 NoSQL 패턴 구현, 실시간 동기화 및 오프라인 캐싱을 위한 Firebase Firestore 전문 지식을 제공합니다. 보안 규칙 구성, 실시간 리스너 설정 또는 오프라인 지원 애플리케이션 구축 시 활용하세요. 문서 모델링과 모바일 최적화 SDK를 포함한 Firestore의 핵심 기능을 다룹니다.

빠른 설치

Claude Code

추천
기본
npx skills add modu-ai/moai-adk
플러그인 명령대체
/plugin add https://github.com/modu-ai/moai-adk
Git 클론대체
git clone https://github.com/modu-ai/moai-adk.git ~/.claude/skills/moai-platform-firestore

Claude Code에서 이 명령을 복사하여 붙여넣어 스킬을 설치하세요

문서

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 저장소

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

연관 스킬

mobile-testing

기타

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.

스킬 보기

moai-domain-mobile-app

테스팅

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.

스킬 보기

moai-domain-mobile-app

테스팅

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.

스킬 보기

moai-lang-flutter

기타

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.

스킬 보기