Claude Code से Firestore Schema Design: GCP/Firebase SaaS Guide
Claude Code के साथ Firestore collections, rules, indexes और SaaS schema सुरक्षित तरीके से design करें।
Firestore design collection name से नहीं, read pattern से शुरू करें
मैं Masa हूं, claudecode-lab.com चलाता हूं।
Firestore सीखते समय मेरी पहली गलती बहुत सामान्य थी। मैंने पहले users, projects, events, subscriptions जैसी collections बना दीं। शुरुआत में schema साफ दिखा, लेकिन SaaS screens बढ़ते ही समस्या आई: user के projects, project members, recent events, trial users, billing status और admin view. Structure अच्छा दिख रहा था, पर queries product से match नहीं कर रही थीं।
Firestore relational database नहीं है जहां बाद में JOIN से सब ठीक कर देंगे। Official data model के अनुसार data documents में रहता है और documents collections में रहते हैं। Document में fields, objects और subcollections हो सकते हैं। आसान भाषा में: collection एक shelf है, document एक file है, और subcollection उस file के अंदर की छोटी folder है।
इसलिए सही क्रम है: screens, queries, schema, Security Rules, indexes. Claude Code को code generator की तरह नहीं, local design reviewer की तरह इस्तेमाल करें। उसे firestore.rules, firestore.indexes.json, TypeScript types और query functions साथ में दिखाएं ताकि वह contradictions पकड़ सके।
SaaS के लिए collections, documents और subcollections
एक छोटे B2B SaaS के लिए यह structure practical है:
users/{uid}
projects/{projectId}
projects/{projectId}/members/{uid}
projects/{projectId}/events/{eventId}
subscriptions/{uid}
billingCustomers/{uid}
| Path | काम | Typical read |
|---|---|---|
users/{uid} | user profile | current user profile |
projects/{projectId} | workspace या customer project | project detail |
projects/{projectId}/members/{uid} | project role | member list और permission |
projects/{projectId}/events/{eventId} | activity और audit log | recent project events |
subscriptions/{uid} | plan और payment status | feature gating |
billingCustomers/{uid} | Stripe या billing IDs | server jobs only |
Subcollection तभी रखें जब वह common read को आसान बनाती हो। अगर screen हमेशा एक project के 50 recent events पढ़ती है, तो projects/{projectId}/events सही है। अगर cross-project view चाहिए, तो collection group query देख सकते हैं, लेकिन उसके साथ rules और composite index भी design करने होंगे।
Claude Code prompt:
claude -p "
B2B SaaS के Firestore design को review करें।
Collections propose करने से पहले screen-wise query inventory बनाएं।
Screens:
- current user के projects
- project detail
- project के last 50 events
- admin subscription status list
- users whose trial ends soon
हर screen के लिए where/orderBy/limit,
required Composite index और Security Rules condition बताएं।
"
User, project, event और billing schema example
यह TypeScript model Firebase Admin SDK या Cloud Functions के लिए है।
import type { Timestamp } from "firebase-admin/firestore";
export type ProjectRole = "owner" | "admin" | "member" | "viewer";
export type SubscriptionStatus =
| "trialing"
| "active"
| "past_due"
| "canceled";
export interface ProjectDoc {
id: string;
name: string;
ownerUid: string;
plan: "free" | "starter" | "pro";
memberCount: number;
lastEventAt: Timestamp | null;
createdAt: Timestamp;
updatedAt: Timestamp;
}
export interface ProjectMemberDoc {
uid: string;
role: ProjectRole;
displayName: string;
email: string;
joinedAt: Timestamp;
}
export interface ProjectEventDoc {
id: string;
projectId: string;
actorUid: string;
actorName: string;
type: "created" | "updated" | "commented" | "exported";
message: string;
createdAt: Timestamp;
}
export interface SubscriptionDoc {
uid: string;
status: SubscriptionStatus;
plan: "free" | "starter" | "pro";
trialEndsAt: Timestamp | null;
updatedAt: Timestamp;
}
ProjectMemberDoc में displayName और email रखना intentional denormalization है। Denormalization का मतलब है display के लिए छोटे data को copy करना ताकि extra reads कम हों। Firestore में 50 members दिखाने के लिए 50 अलग users/{uid} पढ़ना महंगा हो सकता है। Name copy करने से list fast होती है; profile change पर sync करना पड़ता है।
Example 1: home dashboard के लिए per-user project reference useful है।
users/{uid}/projectRefs/{projectId}
projectId: string
projectName: string
role: "owner" | "admin" | "member" | "viewer"
lastEventAt: Timestamp | null
यह pure normalized model नहीं है, लेकिन first screen को predictable single query बना देता है।
Security Rules filter नहीं हैं
यह सबसे बड़ा trap है। Official secure query documentation साफ कहती है कि Security Rules filters नहीं हैं। Query पूरी allow होती है या पूरी reject. अगर query कोई unauthorized document return कर सकती है, तो query fail होगी।
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /projects/{projectId}/events/{eventId} {
allow list: if request.auth != null
&& exists(/databases/$(database)/documents/projects/$(projectId)/members/$(request.auth.uid))
&& request.query.limit <= 50;
}
}
}
यह query गलत है क्योंकि इसमें limit नहीं है।
import { collection, getDocs } from "firebase/firestore";
await getDocs(collection(db, "projects", projectId, "events"));
सही query rules से match करती है।
import {
collection,
getDocs,
limit,
orderBy,
query,
} from "firebase/firestore";
export async function listProjectEvents(projectId: string) {
const eventsQuery = query(
collection(db, "projects", projectId, "events"),
orderBy("createdAt", "desc"),
limit(50),
);
const snap = await getDocs(eventsQuery);
return snap.docs.map((doc) => ({ id: doc.id, ...doc.data() }));
}
Example 2: अगर rule सिर्फ visibility == "public" allow करती है, तो query में भी where("visibility", "==", "public") होना चाहिए। Firestore अपने आप private documents हटाकर public वाले return नहीं करता।
Composite index और collection group query
Firestore basic indexes बना देता है, लेकिन कई filters और sorting साथ हों तो composite index चाहिए। Official indexing documentation बताती है कि missing index होने पर error में create link मिल सकता है। Team project में firestore.indexes.json को Git में रखना बेहतर है।
{
"indexes": [
{
"collectionGroup": "events",
"queryScope": "COLLECTION_GROUP",
"fields": [
{ "fieldPath": "projectId", "order": "ASCENDING" },
{ "fieldPath": "createdAt", "order": "DESCENDING" }
]
},
{
"collectionGroup": "subscriptions",
"queryScope": "COLLECTION",
"fields": [
{ "fieldPath": "status", "order": "ASCENDING" },
{ "fieldPath": "trialEndsAt", "order": "ASCENDING" }
]
}
],
"fieldOverrides": []
}
Collection group query एक ही ID वाली सभी subcollections पर query चलाती है।
import {
collectionGroup,
getDocs,
limit,
orderBy,
query,
where,
} from "firebase/firestore";
export async function listRecentEventsAcrossProjects(projectId: string) {
const eventsQuery = query(
collectionGroup(db, "events"),
where("projectId", "==", projectId),
orderBy("createdAt", "desc"),
limit(50),
);
const snap = await getDocs(eventsQuery);
return snap.docs.map((doc) => ({ id: doc.id, ...doc.data() }));
}
Rules भी उसी pattern को cover करें। Official rules structure बताती है कि match document path पर होता है, collection पर नहीं। Collection group query के लिए rules version 2 और recursive wildcard का design चाहिए।
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
function signedIn() {
return request.auth != null;
}
function isProjectMember(projectId) {
return signedIn()
&& exists(/databases/$(database)/documents/projects/$(projectId)/members/$(request.auth.uid));
}
match /{path=**}/events/{eventId} {
allow list: if signedIn()
&& request.query.limit <= 50
&& resource.data.projectId is string
&& isProjectMember(resource.data.projectId);
}
}
}
Emulator में test करें। अगर बाद में email logs या billing logs भी events नाम से बना दिए, collection group query उन्हें भी छू सकती है। अलग access rules हों तो projectEvents और billingEvents जैसे names बेहतर हैं।
Claude Code से local design review
मैं repo में docs/firestore-schema.md, firestore.rules, firestore.indexes.json, और query functions रखकर यह prompt चलाता हूं।
claude -p "
इस Firestore design को locally review करें।
Files:
- docs/firestore-schema.md
- firestore.rules
- firestore.indexes.json
- src/lib/firestore/queries.ts
Check:
1. हर screen query schema से match करती है?
2. Security Rules को filter की तरह तो नहीं इस्तेमाल किया?
3. list queries में required where/orderBy/limit हैं?
4. Composite index missing या excessive हैं?
5. Collection group query बहुत broad है?
6. Client subscription status बदल सकता है?
7. कौन सा screen बहुत ज्यादा document reads करता है?
Problems, reasons और fixed code दें।
"
Example 3: subscription status. Client को subscriptions/{uid} लिखने की अनुमति न दें। Stripe webhook या Cloud Function server side से लिखे।
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /subscriptions/{uid} {
allow get: if request.auth != null && request.auth.uid == uid;
allow list: if false;
allow create, update, delete: if false;
}
}
}
Server पर भी plan check करें। UI में button छिपाना authorization नहीं है।
import { getFirestore } from "firebase-admin/firestore";
const db = getFirestore();
export async function assertActiveSubscription(uid: string) {
const snap = await db.collection("subscriptions").doc(uid).get();
const data = snap.data();
if (!data || !["trialing", "active"].includes(data.status)) {
throw new Error("Active subscription required");
}
return data;
}
Masa verification note: मैंने contact management, content admin और छोटे SaaS demo में यह flow आजमाया। Collection names से शुरू करने पर बाद में rewrites आए। Query table पहले बनाकर Claude Code से rules और index review कराने पर design जल्दी साफ हुआ। सबसे common failures थे sequential document IDs, rules और queries को अलग-अलग review करना, billing status को users/{uid} में मिलाना, और हर log को events नाम देना।
GCP integration आगे बढ़ाना हो तो Claude Code x GCP Cloud Functions और Claude Code x GCP Cloud Run पढ़ें। API boundary unclear हो तो Claude Code से REST API design useful है। ClaudeCodeLab इन patterns को free PDF, learning material और consultation checklist में बदल रहा है; schema, rules और query list लेकर आएंगे तो review बहुत concrete हो जाएगा।
मुफ़्त 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.