Claude Code Plugins

Community-maintained marketplace

Feedback

firebase-integration

@k002bill2/LiveMetro
0
0

Firebase Firestore, Auth, and Cloud Functions integration for LiveMetro. Use when working with backend services, authentication, or real-time data sync.

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 firebase-integration
description Firebase integration for authentication, Firestore database, and real-time data synchronization. Use when working with Firebase services in the LiveMetro app.

Firebase Integration Guidelines

When to Use This Skill

  • Setting up Firebase authentication
  • Querying Firestore collections
  • Implementing real-time data subscriptions
  • Managing user data in Firebase
  • Handling Firebase errors

Core Services

1. Firestore Database Structure

Collections:
- subwayLines/          # Line metadata (color, name)
- stations/             # Station info with coordinates
- trains/               # Real-time train positions
- trainDelays/          # Delay and disruption alerts
- congestionData/       # Train car congestion levels
- users/                # User preferences and favorites

2. Authentication Pattern

import { auth } from '@/config/firebase';
import {
  signInAnonymously,
  onAuthStateChanged
} from 'firebase/auth';

// Anonymous authentication for basic features
const signIn = async () => {
  try {
    const result = await signInAnonymously(auth);
    return result.user;
  } catch (error) {
    console.error('Auth error:', error);
    throw error;
  }
};

// Listen to auth state changes
onAuthStateChanged(auth, (user) => {
  if (user) {
    // User is signed in
  } else {
    // User is signed out
  }
});

3. Firestore Query Pattern

import { firestore } from '@/config/firebase';
import {
  collection,
  query,
  where,
  getDocs,
  orderBy,
  limit
} from 'firebase/firestore';

// Basic query
const getStations = async (lineId: string) => {
  try {
    const stationsRef = collection(firestore, 'stations');
    const q = query(
      stationsRef,
      where('lineId', '==', lineId),
      orderBy('sequence')
    );

    const snapshot = await getDocs(q);
    return snapshot.docs.map(doc => ({
      id: doc.id,
      ...doc.data()
    }));
  } catch (error) {
    console.error('Firestore query error:', error);
    return [];
  }
};

4. Real-time Subscription Pattern

import { onSnapshot } from 'firebase/firestore';

// Subscribe to real-time updates
const subscribeToTrains = (
  stationId: string,
  callback: (trains: Train[]) => void
): (() => void) => {
  const trainsRef = collection(firestore, 'trains');
  const q = query(
    trainsRef,
    where('currentStationId', '==', stationId)
  );

  const unsubscribe = onSnapshot(
    q,
    (snapshot) => {
      const trains = snapshot.docs.map(doc => ({
        id: doc.id,
        ...doc.data()
      } as Train));
      callback(trains);
    },
    (error) => {
      console.error('Snapshot error:', error);
    }
  );

  return unsubscribe; // Return cleanup function
};

// Usage in component
useEffect(() => {
  const unsubscribe = subscribeToTrains(stationId, setTrains);
  return () => unsubscribe(); // Cleanup on unmount
}, [stationId]);

5. Error Handling

import { FirebaseError } from 'firebase/app';

const handleFirebaseError = (error: unknown): string => {
  if (error instanceof FirebaseError) {
    switch (error.code) {
      case 'permission-denied':
        return 'You do not have permission to access this data';
      case 'unavailable':
        return 'Firebase service is temporarily unavailable';
      case 'unauthenticated':
        return 'Please sign in to continue';
      default:
        return error.message;
    }
  }
  return 'An unexpected error occurred';
};

Service Layer Pattern

trainService.ts Example

class TrainService {
  private static instance: TrainService;

  static getInstance(): TrainService {
    if (!TrainService.instance) {
      TrainService.instance = new TrainService();
    }
    return TrainService.instance;
  }

  async getTrainsByStation(stationId: string): Promise<Train[]> {
    // Implementation
  }

  subscribeToTrainUpdates(
    stationId: string,
    callback: (trains: Train[]) => void
  ): () => void {
    // Implementation with cleanup
  }
}

export const trainService = TrainService.getInstance();

Data Caching Strategy

Multi-tier fallback

/**
 * Priority: Seoul API → Firebase → Local Cache
 */
const getTrainData = async (stationId: string): Promise<Train[]> => {
  try {
    // 1. Try Seoul API (primary source)
    const apiData = await seoulApi.getArrivals(stationId);
    if (apiData.length > 0) {
      await cacheData(stationId, apiData);
      return apiData;
    }
  } catch (error) {
    console.log('Seoul API failed, trying Firebase');
  }

  try {
    // 2. Fallback to Firebase
    const fbData = await trainService.getTrainsByStation(stationId);
    if (fbData.length > 0) {
      return fbData;
    }
  } catch (error) {
    console.log('Firebase failed, using cache');
  }

  // 3. Last resort: Local cache
  return await getCachedData(stationId);
};

Security Rules Considerations

Firestore Rules Pattern

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Public read for subway data
    match /stations/{stationId} {
      allow read: if true;
      allow write: if false; // Only through admin
    }

    // User-specific data
    match /users/{userId} {
      allow read, write: if request.auth.uid == userId;
    }
  }
}

Best Practices

1. Subscription Cleanup

Always clean up Firebase subscriptions to prevent memory leaks:

useEffect(() => {
  const unsubscribe = subscribeToData(callback);
  return () => unsubscribe();
}, [dependencies]);

2. Batch Operations

For multiple writes, use batch operations:

import { writeBatch } from 'firebase/firestore';

const batch = writeBatch(firestore);
batch.set(docRef1, data1);
batch.update(docRef2, data2);
await batch.commit();

3. Offline Persistence

Handle offline scenarios gracefully:

import { enableNetwork, disableNetwork } from 'firebase/firestore';

// Firestore automatically caches data for offline use
// Monitor connectivity and inform users

Common Pitfalls to Avoid

  • ❌ Not cleaning up subscriptions (memory leaks)
  • ❌ Querying without indexes (slow performance)
  • ❌ Exposing Firebase config in client code (security)
  • ❌ Not handling permission errors
  • ❌ Over-fetching data (use limit and pagination)

Testing

  • Mock Firebase services in tests
  • Test offline scenarios
  • Verify subscription cleanup
  • Test error handling paths