Claude Code के साथ Firebase विकास: Auth, Rules, Functions और Hosting
Claude Code से Firebase ऐप बनाएं: Auth, Firestore Rules, Functions, Hosting, Emulator Suite, environment separation, cost और security सहित।
Claude Code को Firebase काम देने से पहले क्या तय करें
Firebase छोटे प्रोडक्ट और तेज़ टीमों के लिए बहुत उपयोगी BaaS है। BaaS का मतलब है Backend as a Service, यानी authentication, database, functions और hosting जैसी backend क्षमताएं सेवा के रूप में इस्तेमाल करना। व्यवहार में Firebase Authentication, Cloud Firestore, Cloud Functions for Firebase, Firebase Hosting और Local Emulator Suite एक साथ इस्तेमाल किए जाते हैं।
लेकिन Firebase में सबसे बड़ा जोखिम यह है कि ऐप चलने लगे, फिर भी सुरक्षित न हो। Firestore Security Rules ढीले हों तो एक user दूसरे user का data पढ़ सकता है। Cloud Functions में Admin SDK इस्तेमाल करने पर Security Rules लागू नहीं होते, इसलिए function के अंदर authorization फिर से जांचना पड़ता है। Dev और production project गड़बड़ हो जाएं तो local test भी real data और real bill बना सकता है।
Claude Code को काम देते समय सिर्फ “एक form बना दो” न कहें। बेहतर है कि पूरा vertical slice दें: support ticket feature में UI, login state, Firestore write, Security Rules, Emulator Suite tests, privileged Cloud Function और Hosting config शामिल हों।
बुनियादी संदर्भ के लिए authentication implementation guide, deployment flow के लिए CI/CD setup guide, और backend विकल्पों की तुलना के लिए Supabase integration guide भी उपयोगी हैं।
flowchart LR
A["User"] --> B["Firebase Authentication"]
B --> C["React or Astro UI"]
C --> D["Cloud Firestore"]
D --> E["Security Rules"]
D --> F["Cloud Functions v2"]
C --> G["Firebase Hosting"]
H["Emulator Suite"] --> B
H --> D
H --> F
इस लेख में Vite + React + TypeScript का उदाहरण है। Next.js या Astro में भी यही pattern चलेगा, बस environment variables और routing बदलेंगे।
न्यूनतम architecture और official docs
Firebase में official docs को primary source मानना चाहिए। Security Rules और Emulator Suite के पुराने snippets कभी-कभी compile तो हो जाते हैं, लेकिन permission model गलत हो सकता है।
| क्षेत्र | official link | Claude Code को देने लायक scope |
|---|---|---|
| Authentication | Firebase Authentication | Login UI, user profile, auth state |
| Firestore | Cloud Firestore | Collection design, queries, indexes |
| Security Rules | Firestore Security Rules | Rules, denied tests, owner checks |
| Cloud Functions | Cloud Functions for Firebase | Server validation, notifications, aggregation |
| Hosting | Firebase Hosting | SPA deploy, cache, preview channels |
| Emulator | Local Emulator Suite | Local tests, rule coverage, CI |
| Pricing | Firebase pricing | Reads, writes, functions, logs |
| Claude Code | Claude Code docs | Task size, review, test execution |
Claude Code को पहले यह project structure पढ़ने दें:
.
├─ firebase.json
├─ firestore.rules
├─ firestore.indexes.json
├─ .firebaserc
├─ functions/
│ ├─ package.json
│ └─ src/index.ts
└─ src/
├─ lib/firebase.ts
├─ lib/tickets.ts
└─ lib/useAuth.tsx
Environment separation पहले करें
Firebase की कई गलतियां code logic से नहीं, project mix-up से होती हैं। Dev, staging और production को साफ अलग करें और Claude Code को production deploy न चलाने की हिदायत दें।
{
"projects": {
"dev": "claudecodelab-firebase-dev",
"stg": "claudecodelab-firebase-stg",
"prod": "claudecodelab-firebase-prod"
}
}
firebase.json में Firestore rules, indexes, Functions, Hosting और emulators को version control में रखें।
{
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
},
"functions": [
{
"source": "functions",
"codebase": "default",
"runtime": "nodejs20"
}
],
"hosting": {
"public": "dist",
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"headers": [
{
"source": "/assets/**",
"headers": [
{
"key": "Cache-Control",
"value": "public, max-age=31536000, immutable"
}
]
}
],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
},
"emulators": {
"auth": {
"port": 9099
},
"functions": {
"port": 5001
},
"firestore": {
"port": 8080
},
"hosting": {
"port": 5000
},
"ui": {
"enabled": true,
"port": 4000
},
"singleProjectMode": true
}
}
Vite project में .env.local कुछ ऐसा होगा। Firebase Web API key server secret नहीं है, लेकिन service account JSON और Admin SDK credentials secret हैं।
VITE_FIREBASE_API_KEY=replace-me
VITE_FIREBASE_AUTH_DOMAIN=claudecodelab-firebase-dev.firebaseapp.com
VITE_FIREBASE_PROJECT_ID=claudecodelab-firebase-dev
VITE_FIREBASE_STORAGE_BUCKET=claudecodelab-firebase-dev.appspot.com
VITE_FIREBASE_APP_ID=replace-me
VITE_USE_FIREBASE_EMULATORS=true
Authentication और client initialization
यह file Firebase App, Auth, Firestore और Functions initialize करती है और development में emulators से connect करती है।
// src/lib/firebase.ts
import { initializeApp, getApp, getApps } from "firebase/app";
import {
connectAuthEmulator,
getAuth,
GoogleAuthProvider,
} from "firebase/auth";
import { connectFirestoreEmulator, getFirestore } from "firebase/firestore";
import { connectFunctionsEmulator, getFunctions } from "firebase/functions";
const firebaseConfig = {
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
appId: import.meta.env.VITE_FIREBASE_APP_ID,
};
const app = getApps().length > 0 ? getApp() : initializeApp(firebaseConfig);
export const auth = getAuth(app);
export const db = getFirestore(app);
export const functions = getFunctions(app, "asia-northeast1");
export const googleProvider = new GoogleAuthProvider();
const shouldUseEmulators =
import.meta.env.DEV && import.meta.env.VITE_USE_FIREBASE_EMULATORS === "true";
const globalState = globalThis as typeof globalThis & {
__firebaseEmulatorsConnected?: boolean;
};
if (shouldUseEmulators && !globalState.__firebaseEmulatorsConnected) {
connectAuthEmulator(auth, "http://127.0.0.1:9099", {
disableWarnings: true,
});
connectFirestoreEmulator(db, "127.0.0.1", 8080);
connectFunctionsEmulator(functions, "127.0.0.1", 5001);
globalState.__firebaseEmulatorsConnected = true;
}
Auth state को Hook में रखें। पहली login पर users/{uid} profile merge करें, ताकि बाद में ownership rules साफ रहें।
// src/lib/useAuth.tsx
import { useEffect, useState } from "react";
import {
onAuthStateChanged,
signInWithPopup,
signOut,
type User,
} from "firebase/auth";
import { doc, serverTimestamp, setDoc } from "firebase/firestore";
import { auth, db, googleProvider } from "./firebase";
type AuthState = {
user: User | null;
loading: boolean;
signInWithGoogle: () => Promise<void>;
logout: () => Promise<void>;
};
export function useAuth(): AuthState {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
return onAuthStateChanged(auth, (currentUser) => {
setUser(currentUser);
setLoading(false);
});
}, []);
async function signInWithGoogle() {
const result = await signInWithPopup(auth, googleProvider);
await setDoc(
doc(db, "users", result.user.uid),
{
uid: result.user.uid,
email: result.user.email,
displayName: result.user.displayName,
photoURL: result.user.photoURL,
updatedAt: serverTimestamp(),
},
{ merge: true },
);
}
return {
user,
loading,
signInWithGoogle,
logout: () => signOut(auth),
};
}
Claude Code को ऐसा prompt दें:
Firebase Auth के साथ Google login implement करें।
- Stack Vite + React + TypeScript है
- existing src/lib/firebase.ts reuse करें
- first login पर users/{uid} merge करें
- logout function return करें
- service account credentials create, display या store न करें
- implementation के बाद type errors, Firestore Rules impact और manual checks बताएं
Firestore data model और CRUD
Example feature support ticket system है। इसके तीन use cases हैं: member portal जहां user अपने tickets देखता है; support workflow जहां Cloud Function ticket close करती है; और admin dashboard जहां new ticket पर notification और metrics बनते हैं।
// src/lib/tickets.ts
import {
addDoc,
collection,
getDocs,
limit,
orderBy,
query,
serverTimestamp,
where,
type Timestamp,
} from "firebase/firestore";
import { db } from "./firebase";
export type TicketStatus = "open" | "closed";
export type Ticket = {
id: string;
userId: string;
title: string;
body: string;
status: TicketStatus;
createdAt: Timestamp;
updatedAt: Timestamp;
};
type CreateTicketInput = {
userId: string;
title: string;
body: string;
};
export async function createTicket(input: CreateTicketInput): Promise<string> {
const title = input.title.trim();
const body = input.body.trim();
if (title.length === 0 || title.length > 120) {
throw new Error("Title must be between 1 and 120 characters.");
}
if (body.length === 0 || body.length > 4000) {
throw new Error("Body must be between 1 and 4000 characters.");
}
const docRef = await addDoc(collection(db, "tickets"), {
userId: input.userId,
title,
body,
status: "open",
createdAt: serverTimestamp(),
updatedAt: serverTimestamp(),
});
return docRef.id;
}
export async function listMyTickets(userId: string): Promise<Ticket[]> {
const ticketsQuery = query(
collection(db, "tickets"),
where("userId", "==", userId),
orderBy("createdAt", "desc"),
limit(20),
);
const snapshot = await getDocs(ticketsQuery);
return snapshot.docs.map((ticketDoc) => ({
id: ticketDoc.id,
...(ticketDoc.data() as Omit<Ticket, "id">),
}));
}
इस query के लिए composite index चाहिए हो सकता है, इसलिए index को repo में रखें।
{
"indexes": [
{
"collectionGroup": "tickets",
"queryScope": "COLLECTION",
"fields": [
{
"fieldPath": "userId",
"order": "ASCENDING"
},
{
"fieldPath": "createdAt",
"order": "DESCENDING"
}
]
}
],
"fieldOverrides": []
}
Firestore Security Rules filter नहीं हैं
Security Rules broad query को safe documents में filter नहीं करते। Query खुद ऐसी होनी चाहिए कि उसके सारे possible results allowed हों। इसलिए पूरी tickets collection पढ़कर React में filter करना गलत है।
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
function signedIn() {
return request.auth != null;
}
function isOwner(userId) {
return signedIn() && request.auth.uid == userId;
}
function ticketFieldsAreValid() {
return request.resource.data.keys().hasOnly([
"userId",
"title",
"body",
"status",
"createdAt",
"updatedAt"
])
&& request.resource.data.title is string
&& request.resource.data.title.size() > 0
&& request.resource.data.title.size() <= 120
&& request.resource.data.body is string
&& request.resource.data.body.size() > 0
&& request.resource.data.body.size() <= 4000;
}
match /users/{userId} {
allow create, read, update: if isOwner(userId);
allow delete: if false;
}
match /tickets/{ticketId} {
allow create: if signedIn()
&& request.resource.data.userId == request.auth.uid
&& request.resource.data.status == "open"
&& ticketFieldsAreValid();
allow read: if signedIn()
&& resource.data.userId == request.auth.uid;
allow update: if signedIn()
&& resource.data.userId == request.auth.uid
&& request.resource.data.userId == resource.data.userId
&& request.resource.data.status == resource.data.status
&& request.resource.data.diff(resource.data).affectedKeys()
.hasOnly(["title", "body", "updatedAt"])
&& ticketFieldsAreValid();
allow delete: if false;
}
match /adminStats/{docId} {
allow read, write: if false;
}
}
}
Review में देखें कि request.auth.uid owner से compare हो रहा है, extra fields block हैं, delete बंद है, और admin data client के लिए खुला नहीं है।
Emulator Suite से rules test करें
npm install -D vitest @firebase/rules-unit-testing firebase
firebase setup:emulators:firestore
// tests/firestore.rules.test.ts
import { readFileSync } from "node:fs";
import {
assertFails,
assertSucceeds,
initializeTestEnvironment,
type RulesTestEnvironment,
} from "@firebase/rules-unit-testing";
import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { doc, getDoc, setDoc, updateDoc } from "firebase/firestore";
let testEnv: RulesTestEnvironment;
beforeAll(async () => {
testEnv = await initializeTestEnvironment({
projectId: "claudecodelab-firestore-rules",
firestore: {
rules: readFileSync("firestore.rules", "utf8"),
},
});
});
beforeEach(async () => {
await testEnv.clearFirestore();
});
afterAll(async () => {
await testEnv.cleanup();
});
describe("tickets security rules", () => {
it("allows the owner to create and read a ticket", async () => {
const aliceDb = testEnv.authenticatedContext("alice").firestore();
const ticketRef = doc(aliceDb, "tickets/ticket-1");
await assertSucceeds(
setDoc(ticketRef, {
userId: "alice",
title: "Please resend my invoice",
body: "I cannot find the April invoice.",
status: "open",
createdAt: new Date(),
updatedAt: new Date(),
}),
);
await assertSucceeds(getDoc(ticketRef));
});
it("blocks another user from reading the ticket", async () => {
await testEnv.withSecurityRulesDisabled(async (context) => {
await setDoc(doc(context.firestore(), "tickets/ticket-2"), {
userId: "alice",
title: "Plan question",
body: "I want to confirm my current plan.",
status: "open",
createdAt: new Date(),
updatedAt: new Date(),
});
});
const bobDb = testEnv.authenticatedContext("bob").firestore();
await assertFails(getDoc(doc(bobDb, "tickets/ticket-2")));
});
it("blocks status changes from the web client", async () => {
await testEnv.withSecurityRulesDisabled(async (context) => {
await setDoc(doc(context.firestore(), "tickets/ticket-3"), {
userId: "alice",
title: "Cannot sign in",
body: "Google sign-in returns an error.",
status: "open",
createdAt: new Date(),
updatedAt: new Date(),
});
});
const aliceDb = testEnv.authenticatedContext("alice").firestore();
await assertFails(
updateDoc(doc(aliceDb, "tickets/ticket-3"), {
status: "closed",
updatedAt: new Date(),
}),
);
});
it("keeps the test runner alive", () => {
expect(testEnv).toBeDefined();
});
});
{
"scripts": {
"dev": "vite",
"build": "vite build",
"firebase:use:dev": "firebase use dev",
"firebase:emulators": "firebase emulators:start --only auth,firestore,functions,hosting",
"test:rules": "firebase emulators:exec --only firestore \"vitest run tests/firestore.rules.test.ts\"",
"deploy:stg": "firebase use stg && npm run build && firebase deploy --only hosting,firestore:rules,firestore:indexes,functions",
"deploy:prod": "firebase use prod && npm run build && firebase deploy --only hosting,firestore:rules,firestore:indexes,functions"
}
}
Privileged काम Cloud Functions में रखें
State changes, external API keys, notifications और aggregation browser पर भरोसा करके नहीं करने चाहिए।
// functions/src/index.ts
import { initializeApp } from "firebase-admin/app";
import { FieldValue, getFirestore } from "firebase-admin/firestore";
import { onDocumentCreated } from "firebase-functions/v2/firestore";
import { HttpsError, onCall } from "firebase-functions/v2/https";
initializeApp();
const db = getFirestore();
export const closeTicket = onCall(
{
region: "asia-northeast1",
},
async (request) => {
if (!request.auth) {
throw new HttpsError("unauthenticated", "Sign-in is required.");
}
const ticketId = request.data?.ticketId;
if (typeof ticketId !== "string" || ticketId.length > 100) {
throw new HttpsError("invalid-argument", "ticketId is invalid.");
}
const ticketRef = db.doc(`tickets/${ticketId}`);
const ticketSnap = await ticketRef.get();
if (!ticketSnap.exists) {
throw new HttpsError("not-found", "Ticket was not found.");
}
const ticket = ticketSnap.data();
if (ticket?.userId !== request.auth.uid) {
throw new HttpsError("permission-denied", "You cannot close this ticket.");
}
await ticketRef.update({
status: "closed",
closedAt: FieldValue.serverTimestamp(),
updatedAt: FieldValue.serverTimestamp(),
});
return { ok: true };
},
);
export const notifyTicketCreated = onDocumentCreated(
{
document: "tickets/{ticketId}",
region: "asia-northeast1",
},
async (event) => {
const ticket = event.data?.data();
if (!ticket) return;
await db.collection("adminNotifications").add({
type: "ticket_created",
ticketId: event.params.ticketId,
title: ticket.title,
userId: ticket.userId,
createdAt: FieldValue.serverTimestamp(),
read: false,
});
},
);
मुख्य बात: Admin SDK Security Rules को bypass करता है। इसलिए हर Callable Function में request.auth, input type और document owner check होना चाहिए।
Hosting, cost और security review
firebase login
firebase use dev
npm run build
firebase emulators:start --only auth,firestore,functions,hosting
firebase hosting:channel:deploy preview-firebase-ticket
firebase use stg
firebase deploy --only hosting,firestore:rules,firestore:indexes,functions
Concrete failure cases याद रखें: हर logged-in user को सब पढ़ने देना; पूरी collection पढ़कर UI में filter करना; Functions में owner check भूलना; Emulator में वही firestore.rules load न होना; और .env.local, firebase use, Firebase Console अलग-अलग projects दिखाना।
Cost के लिए Firebase pricing पर latest numbers देखें। Firestore reads, limit, realtime listener cleanup, Functions region और timeout, logs और Hosting cache review करें। Security में service account JSON, CI token या production Owner role Claude Code prompt में न डालें।
Claude Code prompt template
Firebase support ticket feature implement करें।
Scope:
- Vite + React + TypeScript
- Firebase Auth, Firestore, Cloud Functions v2, Hosting
- सिर्फ src/lib/firebase.ts, src/lib/useAuth.tsx, src/lib/tickets.ts, firestore.rules, functions/src/index.ts, firebase.json edit करें
Requirements:
- Google login users tickets create कर सकते हैं
- Users सिर्फ अपने tickets पढ़ सकते हैं
- Web client status change नहीं कर सकता
- Callable Function owner validation के बाद ticket close करती है
- Emulator Suite tests allowed और denied access दोनों के लिए जोड़ें
- dev/stg/prod projects अलग रखें
Forbidden:
- service account JSON create, print या save न करें
- production deploy न चलाएं
- allow read, write: if true इस्तेमाल न करें
Report:
- changed files
- tests run
- Security Rules permission boundary
- remaining manual checks
निष्कर्ष
Claude Code और Firebase का मेल अच्छा है क्योंकि rules, functions, indexes, hosting config और client SDK calls सब reviewable diffs बनाते हैं। फिर भी permissions, production deploy, data ownership और cost boundary पर अंतिम निर्णय इंसान को लेना चाहिए।
असल project में पहले Emulator Suite में एक छोटा vertical feature बनाएं, Security Rules के negative tests जोड़ें, Cloud Functions authorization review करें, फिर Hosting preview, staging और production की तरफ बढ़ें। ClaudeCodeLab Firebase implementation, Security Rules review, Emulator Suite training और Claude Code team workflow बनाने में मदद कर सकता है।
इस लेख की चीजें try करते समय यह जरूर जांचें कि आप development Firebase project इस्तेमाल कर रहे हैं, firebase use और .env.local match करते हैं, Security Rules के success और failure tests pass हैं, Cloud Functions owner validation करती है, और Claude Code को production deploy automatically चलाने की अनुमति नहीं है।
मुफ़्त PDF: Claude Code cheatsheet
Email डालें और commands, review habits तथा safe workflow वाली एक-page PDF पाएँ.
हम आपका data सुरक्षित रखते हैं और spam नहीं भेजते.
लेखक के बारे में
Masa
Claude Code workflow और team adoption पर काम करने वाला engineer.
संबंधित लेख
Claude Code Obsidian to CLAUDE.md workflow: context बार-बार न समझाएं
Obsidian notes को CLAUDE.md operating notes में बदलकर Claude Code sessions को resume करना आसान बनाएं.
Claude Code Revenue CTA Routing: article से PDF, Gumroad और consultation तक
Reader intent के आधार पर free PDF, Gumroad products और consultation तक CTA route करने वाला workflow.
Claude Code टीम हैंडऑफ नियम: review proof, permissions, rollback और revenue path
Claude Code टीम काम के लिए evidence, permission rules, rollback, free PDF, Gumroad और consultation path वाला handoff.