firebase-integration
This repository contains a complete **Cursor (Claude AI)** infrastructure that provides **auto-activating skills**, **specialized agents**, and **powerful commands** to help you build better applications faster.
- Category: discovered
- Tags: github, community
- Version: 1.0.0
- Author: walid
- Downloads: 0
- Updated: 2025-11-22
Download the latest version (v1.0.0) from this page.
SKILL.md
# Firebase Integration Guidelines
**Skill Version:** 1.0.0
**Stack:** Firebase (Firestore, Auth, Storage)
**Purpose:** Guidelines for integrating Firebase services
## Overview
This skill provides comprehensive guidelines for integrating Firebase services into your Next.js application, including Firestore database, Authentication, and Cloud Storage.
## When to Use This Skill
Load this skill when working on:
- Firebase configuration and initialization
- Firestore database operations
- Firebase Authentication
- Cloud Storage file operations
- Real-time listeners
- Security rules
## Project Structure
```
lib/
├── firebase/
│ ├── config.ts # Firebase initialization
│ ├── auth.ts # Auth helpers
│ ├── firestore.ts # Firestore helpers
│ └── storage.ts # Storage helpers
app/
├── api/
│ └── firebase/ # Server-side Firebase operations
```
## Core Guidelines
### 1. Firebase Configuration
#### Client-Side Configuration
```typescript
// lib/firebase/config.ts
import { initializeApp, getApps, FirebaseApp } from 'firebase/app';
import { getAuth, Auth } from 'firebase/auth';
import { getFirestore, Firestore } from 'firebase/firestore';
import { getStorage, FirebaseStorage } from 'firebase/storage';
const firebaseConfig = {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
};
// Initialize Firebase (singleton pattern)
let app: FirebaseApp;
let auth: Auth;
let db: Firestore;
let storage: FirebaseStorage;
if (!getApps().length) {
app = initializeApp(firebaseConfig);
auth = getAuth(app);
db = getFirestore(app);
storage = getStorage(app);
} else {
app = getApps()[0];
auth = getAuth(app);
db = getFirestore(app);
storage = getStorage(app);
}
export { app, auth, db, storage };
```
#### Server-Side Configuration (Firebase Admin)
```typescript
// lib/firebase/admin.ts
import { initializeApp, getApps, cert, App } from 'firebase-admin/app';
import { getAuth, Auth } from 'firebase-admin/auth';
import { getFirestore, Firestore } from 'firebase-admin/firestore';
import { getStorage, Storage } from 'firebase-admin/storage';
let adminApp: App;
let adminAuth: Auth;
let adminDb: Firestore;
let adminStorage: Storage;
if (!getApps().length) {
adminApp = initializeApp({
credential: cert({
projectId: process.env.FIREBASE_PROJECT_ID,
clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
privateKey: process.env.FIREBASE_PRIVATE_KEY?.replace(/\\n/g, '\n'),
}),
storageBucket: process.env.FIREBASE_STORAGE_BUCKET,
});
adminAuth = getAuth(adminApp);
adminDb = getFirestore(adminApp);
adminStorage = getStorage(adminApp);
} else {
adminApp = getApps()[0];
adminAuth = getAuth(adminApp);
adminDb = getFirestore(adminApp);
adminStorage = getStorage(adminApp);
}
export { adminApp, adminAuth, adminDb, adminStorage };
```
### 2. Firestore Database Operations
#### Basic CRUD Operations
```typescript
// lib/firebase/firestore.ts
import {
collection,
doc,
getDoc,
getDocs,
addDoc,
updateDoc,
deleteDoc,
query,
where,
orderBy,
limit,
DocumentData,
QueryConstraint
} from 'firebase/firestore';
import { db } from './config';
// Create
export async function createDocument<T extends DocumentData>(
collectionName: string,
data: T
) {
try {
const docRef = await addDoc(collection(db, collectionName), {
...data,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
});
return { id: docRef.id, ...data };
} catch (error) {
console.error('Error creating document:', error);
throw error;
}
}
// Read single document
export async function getDocument<T>(
collectionName: string,
docId: string
): Promise<T | null> {
try {
const docRef = doc(db, collectionName, docId);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
return { id: docSnap.id, ...docSnap.data() } as T;
}
return null;
} catch (error) {
console.error('Error getting document:', error);
throw error;
}
}
// Read multiple documents with query
export async function getDocuments<T>(
collectionName: string,
constraints: QueryConstraint[] = []
): Promise<T[]> {
try {
const q = query(collection(db, collectionName), ...constraints);
const querySnapshot = await getDocs(q);
return querySnapshot.docs.map(doc => ({
id: doc.id,
...doc.data()
})) as T[];
} catch (error) {
console.error('Error getting documents:', error);
throw error;
}
}
// Update
export async function updateDocument(
collectionName: string,
docId: string,
data: Partial<DocumentData>
) {
try {
const docRef = doc(db, collectionName, docId);
await updateDoc(docRef, {
...data,
updatedAt: new Date().toISOString(),
});
} catch (error) {
console.error('Error updating document:', error);
throw error;
}
}
// Delete
export async function deleteDocument(
collectionName: string,
docId: string
) {
try {
const docRef = doc(db, collectionName, docId);
await deleteDoc(docRef);
} catch (error) {
console.error('Error deleting document:', error);
throw error;
}
}
```
#### Real-time Listeners
```typescript
import { onSnapshot, doc, collection } from 'firebase/firestore';
import { db } from './config';
// Listen to a single document
export function listenToDocument<T>(
collectionName: string,
docId: string,
callback: (data: T | null) => void
) {
const docRef = doc(db, collectionName, docId);
const unsubscribe = onSnapshot(
docRef,
(docSnap) => {
if (docSnap.exists()) {
callback({ id: docSnap.id, ...docSnap.data() } as T);
} else {
callback(null);
}
},
(error) => {
console.error('Error listening to document:', error);
}
);
return unsubscribe;
}
// Listen to a collection
export function listenToCollection<T>(
collectionName: string,
constraints: QueryConstraint[] = [],
callback: (data: T[]) => void
) {
const q = query(collection(db, collectionName), ...constraints);
const unsubscribe = onSnapshot(
q,
(querySnapshot) => {
const data = querySnapshot.docs.map(doc => ({
id: doc.id,
...doc.data()
})) as T[];
callback(data);
},
(error) => {
console.error('Error listening to collection:', error);
}
);
return unsubscribe;
}
```
### 3. Firebase Authentication
```typescript
// lib/firebase/auth.ts
import {
createUserWithEmailAndPassword,
signInWithEmailAndPassword,
signOut,
onAuthStateChanged,
GoogleAuthProvider,
signInWithPopup,
User,
updateProfile
} from 'firebase/auth';
import { auth } from './config';
// Email/Password Sign Up
export async function signUp(email: string, password: string, displayName?: string) {
try {
const userCredential = await createUserWithEmailAndPassword(auth, email, password);
if (displayName) {
await updateProfile(userCredential.user, { displayName });
}
return userCredential.user;
} catch (error: any) {
console.error('Error signing up:', error);
throw new Error(error.message);
}
}
// Email/Password Sign In
export async function signIn(email: string, password: string) {
try {
const userCredential = await signInWithEmailAndPassword(auth, email, password);
return userCredential.user;
} catch (error: any) {
console.error('Error signing in:', error);
throw new Error(error.message);
}
}
// Google Sign In
export async function signInWithGoogle() {
try {
const provider = new GoogleAuthProvider();
const userCredential = await signInWithPopup(auth, provider);
return userCredential.user;
} catch (error: any) {
console.error('Error signing in with Google:', error);
throw new Error(error.message);
}
}
// Sign Out
export async function logOut() {
try {
await signOut(auth);
} catch (error) {
console.error('Error signing out:', error);
throw error;
}
}
// Auth State Observer
export function onAuthStateChange(callback: (user: User | null) => void) {
return onAuthStateChanged(auth, callback);
}
// Get Current User
export function getCurrentUser(): User | null {
return auth.currentUser;
}
```
#### Auth Context Provider
```typescript
// contexts/AuthContext.tsx
'use client';
import { createContext, useContext, useEffect, useState } from 'react';
import { User } from 'firebase/auth';
import { onAuthStateChange } from '@/lib/firebase/auth';
interface AuthContextType {
user: User | null;
loading: boolean;
}
const AuthContext = createContext<AuthContextType>({
user: null,
loading: true,
});
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const unsubscribe = onAuthStateChange((user) => {
setUser(user);
setLoading(false);
});
return unsubscribe;
}, []);
return (
<AuthContext.Provider value={{ user, loading }}>
{children}
</AuthContext.Provider>
);
}
export const useAuth = () => useContext(AuthContext);
```
### 4. Cloud Storage Operations
```typescript
// lib/firebase/storage.ts
import {
ref,
uploadBytes,
uploadBytesResumable,
getDownloadURL,
deleteObject,
listAll,
UploadTaskSnapshot
} from 'firebase/storage';
import { storage } from './config';
// Upload file
export async function uploadFile(
file: File,
path: string,
onProgress?: (progress: number) => void
): Promise<string> {
try {
const storageRef = ref(storage, path);
if (onProgress) {
// Upload with progress tracking
const uploadTask = uploadBytesResumable(storageRef, file);
return new Promise((resolve, reject) => {
uploadTask.on(
'state_changed',
(snapshot: UploadTaskSnapshot) => {
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
onProgress(progress);
},
(error) => reject(error),
async () => {
const downloadURL = await getDownloadURL(uploadTask.snapshot.ref);
resolve(downloadURL);
}
);
});
} else {
// Simple upload
await uploadBytes(storageRef, file);
return await getDownloadURL(storageRef);
}
} catch (error) {
console.error('Error uploading file:', error);
throw error;
}
}
// Delete file
export async function deleteFile(path: string) {
try {
const storageRef = ref(storage, path);
await deleteObject(storageRef);
} catch (error) {
console.error('Error deleting file:', error);
throw error;
}
}
// Get file URL
export async function getFileURL(path: string): Promise<string> {
try {
const storageRef = ref(storage, path);
return await getDownloadURL(storageRef);
} catch (error) {
console.error('Error getting file URL:', error);
throw error;
}
}
// List files in a directory
export async function listFiles(path: string) {
try {
const storageRef = ref(storage, path);
const result = await listAll(storageRef);
const files = await Promise.all(
result.items.map(async (item) => ({
name: item.name,
fullPath: item.fullPath,
url: await getDownloadURL(item),
}))
);
return files;
} catch (error) {
console.error('Error listing files:', error);
throw error;
}
}
```
## Security Best Practices
### 1. Environment Variables
```env
# .env.local
NEXT_PUBLIC_FIREBASE_API_KEY=your-api-key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your-auth-domain
NEXT_PUBLIC_FIREBASE_PROJECT_ID=your-project-id
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your-storage-bucket
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your-sender-id
NEXT_PUBLIC_FIREBASE_APP_ID=your-app-id
# Server-side only (no NEXT_PUBLIC prefix)
FIREBASE_CLIENT_EMAIL=your-service-account-email
FIREBASE_PRIVATE_KEY=your-private-key
```
### 2. Firestore Security Rules
```javascript
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Helper functions
function isAuthenticated() {
return request.auth != null;
}
function isOwner(userId) {
return isAuthenticated() && request.auth.uid == userId;
}
// Users collection
match /users/{userId} {
allow read: if isAuthenticated();
allow write: if isOwner(userId);
}
// Posts collection
match /posts/{postId} {
allow read: if true;
allow create: if isAuthenticated();
allow update, delete: if isOwner(resource.data.userId);
}
}
}
```
### 3. Storage Security Rules
```javascript
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
// User uploads
match /users/{userId}/{allPaths=**} {
allow read: if true;
allow write: if request.auth != null && request.auth.uid == userId;
}
// Public files
match /public/{allPaths=**} {
allow read: if true;
allow write: if request.auth != null;
}
}
}
```
## TypeScript Types
```typescript
// types/firebase.ts
export interface FirebaseUser {
id: string;
email: string;
displayName: string;
photoURL?: string;
createdAt: string;
updatedAt: string;
}
export interface FirebaseDocument {
id: string;
createdAt: string;
updatedAt: string;
}
export interface UploadProgress {
bytesTransferred: number;
totalBytes: number;
progress: number;
}
```
## Common Patterns
### Protected API Route
```typescript
// app/api/users/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { adminAuth } from '@/lib/firebase/admin';
export async function GET(request: NextRequest) {
try {
// Verify Firebase Auth token
const token = request.headers.get('Authorization')?.split('Bearer ')[1];
if (!token) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const decodedToken = await adminAuth.verifyIdToken(token);
const userId = decodedToken.uid;
// Your logic here...
return NextResponse.json({ data: 'success' });
} catch (error) {
console.error('Error:', error);
return NextResponse.json({ error: 'Internal error' }, { status: 500 });
}
}
```
---
**Last Updated:** 2025-01-10
**Maintained By:** Development Team