नो-कोड बैकएंड के लिए मल्टी-टेनेंट SaaS डेटा मॉडल विकल्प
मल्टी-टेनेंट SaaS डेटा मॉडल के विकल्प सुरक्षा, रिपोर्टिंग और प्रदर्शन को प्रभावित करते हैं। tenant_id, अलग स्कीमा, और अलग डेटाबेस के स्पष्ट ट्रैडऑफ़ की तुलना करें।

समस्या: टेनेंट्स को अलग रखना बिना गति घटाए
मल्टी-टेनेंसी का मतलब है एक सॉफ्टवेयर प्रोडक्ट कई ग्राहकों (टेनेंट्स) की सेवा करता है, और हर टेनेंट को केवल अपना डेटा ही दिखना चाहिए। मुश्किल यह है कि यह निरंतर रूप से लागू होना चाहिए: न केवल किसी स्क्रीन पर, बल्कि हर API कॉल, एडमिन पैनल, एक्सपोर्ट और बैकग्राउंड जॉब में भी।
आपका डेटा मॉडल रोज़मर्रा के ऑपरेशंस को अपेक्षित से अधिक प्रभावित करता है। यह परमिशन, रिपोर्टिंग, बढ़ने पर क्वेरी स्पीड और एक “छोटी” बग के जोखिम को निर्धारित करता है। एक फ़िल्टर मिस कर दिया और आप डेटा लीक कर सकते हैं। बहुत सख्ती से अलग कर दिया तो रिपोर्टिंग कठिन हो जाती है।
आम तौर पर मल्टी-टेनेंट SaaS डेटा मॉडल को तीन तरीकों से संरचित किया जाता है:
- एक डेटाबेस जहाँ हर टेबल में
tenant_idशामिल है - एक डेटाबेस के अंदर प्रति टेनेंट अलग स्कीमा
- हर टेनेंट के लिए अलग डेटाबेस
भले ही आप नो-कोड बैकएंड में विज़ुअली बिल्ड कर रहे हों, वही ट्रेडऑफ़ लागू होते हैं। AppMaster जैसी टूल्स आपके डिज़ाइन से असली बैकएंड कोड और डेटाबेस संरचनाएँ जेनरेट करती हैं, इसलिए शुरुआती मॉडलिंग निर्णय जल्दी ही प्रोडक्शन व्यवहार और प्रदर्शन में दिखाई देते हैं।
एक हेल्पडेस्क टूल की कल्पना करें। अगर हर टिकट रो में tenant_id है, तो "सभी खुले टिकट" क्वेरी करना आसान है, लेकिन आपको हर जगह टेनेंट चेक लागू करना होगा। अगर हर टेनेंट का अपना स्कीमा या डेटाबेस है, तो डिफ़ॉल्ट रूप से अलगाव मजबूत होता है, पर क्रॉस-टेनेंट रिपोर्टिंग (जैसे "सभी ग्राहकों में औसत बंद होने का समय") में अधिक मेहनत लगती है।
लक्ष्य ऐसा अलगाव है जिस पर आप भरोसा कर सकें बिना रिपोर्टिंग, सपोर्ट और विकास में अवरोध डाले।
जल्दी से चुनाव करने का तरीका: 4 प्रश्न जो विकल्प घटाते हैं
डेटाबेस थ्योरी से शुरू न करें। पहले यह सोचें कि प्रोडक्ट कैसे इस्तेमाल होगा और हफ्ते-दर-हफ्ते आपको क्या ऑपरेट करना होगा।
चार प्रश्न जो अक्सर उत्तर स्पष्ट कर देते हैं
-
डेटा कितना संवेदनशील है, और क्या आप कड़े नियमों के अंतर्गत हैं? हेल्थकेयर, फाइनेंस और सख्त ग्राहक कॉन्ट्रैक्ट अक्सर आपको मजबूत अलगाव (अलग स्कीमा या अलग डेटाबेस) की ओर धकेलते हैं। यह जोखिम कम कर सकता है और ऑडिट्स आसान बना सकता है।
-
क्या आपको अक्सर क्रॉस-टेनेंट रिपोर्टिंग चाहिए? अगर आप नियमित रूप से "सभी ग्राहकों" के मैट्रिक्स (उपयोग, राजस्व, प्रदर्शन) चाहते हैं, तो एक ही डेटाबेस और
tenant_idसाधारणतः सबसे सरल होता है। अलग डेटाबेस इसके लिए कठिन होते हैं क्योंकि आपको कई जगहों से क्वेरी करके परिणाम जोड़ने पड़ते हैं। -
टेनेंट्स एक-दूसरे से कितने अलग होंगे? अगर टेनेंट्स को कस्टम फ़ील्ड्स, कस्टम वर्कफ़्लो, या अनूठी इंटीग्रेशन चाहिए तो अलग स्कीमा या डेटाबेस बदलावों के फैलने के जोखिम को घटा सकते हैं। अगर ज़्यादातर टेनेंट एक ही संरचना साझा करते हैं, तो
tenant_idसाफ़ रहता है। -
आपकी टीम वास्तविक रूप से क्या ऑपरेट कर सकती है? अधिक अलगाव का मतलब आम तौर पर अधिक काम होता है: अधिक बैकअप, अधिक माइग्रेशन्स, अधिक घटक और अधिक जगहें जहाँ फेलियर छिप सकते हैं।
व्यावहारिक तरीका यह है कि अपने शीर्ष दो विकल्पों का प्रोटोटाइप बनाएं, फिर असली दर्द बिंदुओं—परमिशन नियम, रिपोर्टिंग क्वेरियाँ, और मॉडल के बढ़ने पर बदलाव कैसे रोल आउट होते हैं—को टेस्ट करें।
तरीका 1: एक डेटाबेस, हर रो पर tenant_id
यह सबसे सामान्य सेटअप है: सभी ग्राहक एक ही टेबल्स साझा करते हैं, और हर टेनेंट-स्वामित्व रिकॉर्ड में tenant_id होता है। यह ऑपरेशनल रूप से सरल है क्योंकि आप एक डेटाबेस और एक सेट माइग्रेशन्स चलाते हैं।
नियम सख्त है: अगर कोई रो किसी टेनेंट की है, तो उसमें tenant_id होना चाहिए, और हर क्वेरी को इससे फ़िल्टर करना चाहिए। टेनेंट-स्वामित्व तालिकाओं में आम तौर पर users, roles, projects, tickets, invoices, messages, file metadata, और उन जॉइन तालिकाओं शामिल होती हैं जो टेनेंट डेटा को जोड़ती हैं।
लीक्स को कम करने के लिए tenant_id को गैर-वार्तालापीय मानें:
- टेनेंट-स्वामित्व तालिकाओं पर
tenant_idआवश्यक (NOT NULL) रखें - ऐसे इंडेक्स जोड़ें जो
tenant_idसे शुरू होते हैं (उदाहरण के लिए,tenant_id, created_at) - यूनिक नियमों में
tenant_idशामिल करें (जैसे प्रति टेनेंट यूनिक ईमेल) tenant_idहर API और बिज़नेस फ्लो के माध्यम से पास करें, सिर्फ़ UI फ़ॉर्म्स नहीं- इसे केवल क्लाइंट-साइड फ़िल्टर पर निर्भर न रखें, बैकएंड में लागू करें
PostgreSQL में, रो-लेवल सिक्योरिटी पॉलिसीज़ एक मजबूत सेफ़्टी नेट जोड़ सकती हैं, विशेषकर जब क्वेरियाँ डायनामिक रूप से जेनरेट होती हैं।
रेफरेंस डेटा आमतौर पर दो बकेट में आता है: साझा तालिकाएँ (जैसे countries) जिनमें tenant_id नहीं होता, और टेनेंट-स्कोप्ड कैटलॉग्स (जैसे कस्टम टैग्स या पाइपलाइन) जिनमें tenant_id होता है।
अगर आप AppMaster के साथ बना रहे हैं, तो एक सरल आदत अधिकांश घटनाओं को रोकेगी: प्रमाणीकृत उपयोगकर्ता के टेनेंट से tenant_id को किसी भी क्रिएट या रीड से पहले अपने Business Process लॉजिक में सेट करें, और इस पैटर्न को लगातार रखें।
परमिशन्स प्रभाव: हर दृष्टिकोण से क्या बदलता है
परमिशन्स वह जगह है जहाँ मल्टी-टेनेंसी सफल होती है या विफल। जो डेटा लेआउट आप चुनते हैं वह यह बदल देता है कि आप यूज़र्स कैसे स्टोर करते हैं, क्वेरियों को कैसे स्कोप करते हैं, और एडमिन स्क्रीन में “ओप्स” पलों से कैसे बचते हैं।
एक सिंगल डेटाबेस और हर रो पर tenant_id के साथ, टीमें अक्सर एक साझा Users तालिका का उपयोग करती हैं और हर उपयोगकर्ता को एक टेनेंट और एक या अधिक रोल्स से जोड़ती हैं। बड़ा नियम वही रहता है: हर रीड और राइट में टेनेंट स्कोप होना चाहिए, यहां तक कि छोटी तालिकाओं जैसे settings, tags, या logs के लिए भी।
अलग स्कीमाओं के साथ, आप अक्सर एक साझा पहचान लेयर (लॉगिन, पासवर्ड, MFA) एक जगह रखते हैं, जबकि टेनेंट डेटा प्रत्येक टेनेंट के स्कीमा में रहता है। परमिशन्स आंशिक रूप से राउटिंग की समस्या बन जाती हैं: ऐप को बिज़नेस लॉजिक चलाने से पहले सही स्कीमा की ओर क्वेरियों को इशारा करना होगा।
अलग डेटाबेस के साथ, अलगाव सबसे मजबूत होता है, पर परमिशन लॉजिक इन्फ्रास्ट्रक्चर की ओर शिफ्ट हो जाता है: सही डेटाबेस कनेक्शन चुनना, क्रेडेंशियल्स मैनेज करना, और “ग्लोबल” स्टाफ अकाउंट्स को हैंडल करना।
इन तीनों दृष्टिकोणों में कुछ पैटर्न लगातार क्रॉस-टेनेंट जोखिम को कम करते हैं:
tenant_idको सेशन या ऑथ टोकन क्लेम्स में डालें और उसे आवश्यक मानें।- टेनेंट चेक्स को एक जगह केंद्रीकृत करें (मिडलवेयर या एक साझा Business Process), हर एंडपॉइंट में बिखरे होने न दें।
- एडमिन टूल्स में टेनेंट संदर्भ स्पष्ट दिखाएँ और स्पष्ट टेनेंट स्विच आवश्यक करें।
- सपोर्ट एक्सेस के लिए इम्पर्सोनेशन का उपयोग करें और ऑडिट लॉग रखें।
AppMaster में, इसका मतलब आम तौर पर प्रमाणिकरण के तुरंत बाद टेनेंट संदर्भ स्टोर करना और API एंडपॉइंट्स तथा Business Processes में उसका पुन:प्रयोग करना है ताकि हर क्वेरी स्कोप्ड रहे। एक सपोर्ट एजेंट केवल उन ऑर्डर्स को तभी देखे जब ऐप ने टेनेंट संदर्भ सेट किया हो, न कि सिर्फ इसलिए कि UI ने ठीक फ़िल्टर किया था।
रिपोर्टिंग और प्रदर्शन — tenant_id मॉडल के साथ
tenant_id सिंगल-डेटाबेस विकल्प में रिपोर्टिंग सामान्यतः सीधी होती है। ग्लोबल डैशबोर्ड (MRR, साइनअप, उपयोग) एक ही क्वेरी चला सकते हैं, और टेनेंट-स्तरीय रिपोर्ट वही क्वेरी सिर्फ़ फ़िल्टर के साथ होती है।
ट्रेडऑफ़ समय के साथ प्रदर्शन है। जैसे-जैसे तालिकाएँ बढ़ती हैं, एक व्यस्त टेनेंट शोरगर पड़ोसी बन सकता है — अधिक रो बनाना, अधिक राइट्स ट्रिगर करना, और सामान्य क्वेरियों को स्लो कर देना अगर डेटाबेस को बहुत अधिक स्कैन करना पड़े।
इंडेक्सिंग इस मॉडल को स्वस्थ रखने में मदद करती है। अधिकांश टेनेंट-स्कोप्ड रीड्स को ऐसे इंडेक्स से सक्षम होना चाहिए जो tenant_id से शुरू होता है, ताकि डेटाबेस उस टेनेंट के डेटा के हिस्से पर सीधे पहुंच सके।
एक अच्छा बेसलाइन:
- कंपोजिट इंडेक्स जोड़ें जहाँ
tenant_idपहला कॉलम हो (उदाहरण:tenant_id + created_at,tenant_id + status,tenant_id + user_id) - केवल उन ग्लोबल इंडेक्स्स को रखें जिनकी आपको क्रॉस-टेनेंट क्वेरी के लिए ज़रूरत है
- जॉइन्स और फ़िल्टर पर ध्यान दें जो
tenant_idभूल जाते हैं, क्योंकि ये स्लो स्कैन का कारण बन सकते हैं
रिटेंशन और डिलीट्स के लिए भी योजना चाहिए क्योंकि एक टेनेंट का इतिहास सभी के लिए तालिकाओं को बढ़ा सकता है। अगर टेनेंट्स की रिटेंशन पॉलिसी अलग-अलग है, तो सॉफ्ट डिलीट्स के साथ प्रति-टेनेंट शेड्यूल्ड आर्काइविंग पर विचार करें, या पुरानी रो को tenant_id से की-की गई आर्काइव तालिका में मूव करें।
तरीका 2: प्रति टेनेंट अलग स्कीमा
अलग स्कीमा के साथ, आप अभी भी एक PostgreSQL डेटाबेस का उपयोग करते हैं, पर हर टेनेंट को अपना स्कीमा मिलता है (उदाहरण: tenant_42)। उस स्कीमा के अंदर की तालिकाएँ केवल उस टेनेंट के हैं। यह हर ग्राहक को एक "मिनी डेटाबेस" देने जैसा महसूस कराता है, बिना कई डेटाबेस चलाने के ओवरहेड के।
आम सेटअप में वैश्विक सर्विसेज़ एक साझा स्कीमा में रखी जाती हैं और टेनेंट डेटा टेनेंट स्कीमाओं में। विभाजन आमतौर पर इस बात पर निर्भर करता है कि क्या साझा होना चाहिए और क्या कभी भी मिश्रित नहीं होना चाहिए।
आम विभाजन:
- साझा स्कीमा: tenants तालिका, plans, billing रिकॉर्ड, feature flags, audit settings
- टेनेंट स्कीमा: बिज़नेस तालिकाएँ जैसे orders, tickets, inventory, projects, custom fields
- किन्हीं मामलों में (प्रोडक्ट पर निर्भर): users और roles, खासकर अगर उपयोगकर्ता कई टेनेंट्स में एक्सेस कर सकते हैं
यह मॉडल क्रॉस-टेनेंट जॉइन्स के जोखिम को घटाता है क्योंकि तालिकाएँ अलग नेमस्पेस में रहती हैं। यह एक स्कीमा लक्षित करके एक टेनेंट का बैकअप या रिस्टोर करना भी आसान बना सकता है।
माइग्रेशन्स टीमों के लिए चौंकाने वाली चीज़ होती हैं। जब आप एक नई टेबल या कॉलम जोड़ते हैं, तो आपको हर टेनेंट स्कीमा में वही बदलाव लागू करना होगा। 10 टेनेंट्स के साथ यह प्रबंधनीय है। 1,000 के साथ, आपको स्कीमा संस्करण ट्रैक करने, बैच में माइग्रेशन्स चलाने और सुरक्षित रूप से फेल होने के लिए प्रोसेस चाहिए ताकि एक टूटी हुई स्कीमा बाकी को ब्लॉक न करे।
ऐसे साझा सेवाएं जैसे auth और billing सामान्यतः टेनेंट स्कीमा के बाहर रहती हैं। एक व्यावहारिक पैटर्न साझा auth (एक user तालिका और एक tenant membership तालिका) और साझा बिलिंग (Stripe ग्राहक IDs, invoices) रखना है, जबकि टेनेंट स्कीमा टेनेंट-स्वामित्व वाला बिज़नेस डेटा स्टोर करते हैं।
AppMaster का उपयोग करते समय, शुरू में यह प्लान करें कि Data Designer मॉडल कैसे साझा बनाम टेनेंट स्कीमा में मैप होंगे, और साझा सेवाओं को स्थिर रखें ताकि टेनेंट स्कीमा बिना लॉगिन या भुगतान तोड़े विकसित हो सकें।
अलग स्कीमा के साथ रिपोर्टिंग और प्रदर्शन
अलग स्कीमा स्वतः tenant_id फिल्टर की तुलना में अधिक मजबूत अलगाव देते हैं क्योंकि तालिकाएँ भौतिक रूप से अलग होती हैं और परमिशन्स स्कीमा-स्तर पर सेट की जा सकती हैं।
जब अधिकांश रिपोर्टें प्रति-टेनेंट हों तो रिपोर्टिंग अच्छी रहती है। क्वेरियाँ साधारण रहती हैं क्योंकि आप एक टेनेंट की तालिकाओं से पढ़ते हैं बिना बार-बार साझा तालिकाओं को फ़िल्टर किए। यह मॉडल "खास" टेनेंट्स का समर्थन भी करता है जिन्हें अतिरिक्त तालिकाएँ या कस्टम कॉलम चाहिए बिना बाकी सभी को वह बोझ उठाने के।
ऑग्मेन्शनल रिपोर्टिंग (सभी टेनेंट्स पर) वही जगह है जहाँ स्कीमा थोड़ी परेशानी करने लगते हैं। या तो आपको कई स्कीमाओं को क्वेरी कर सकने वाली रिपोर्टिंग लेयर चाहिए, या आप साझा समरी तालिकाएँ एक सामान्य स्कीमा में बनाकर रखेंगे।
आम पैटर्न:
- प्रति-टेनेंट डैशबोर्ड जो केवल उस टेनेंट के स्कीमा से क्वेरी करता है
- एक केंद्रीय एनालिटिक्स स्कीमा जिसमें रात भर प्रत्येक टेनेंट से रोलअप होता है
- एक्सपोर्ट जॉब्स जो टेनेंट डेटा को वेयरहाउस-फ्रेंडली फ़ॉर्मेट में कॉपी करते हैं
प्रदर्शन आम तौर पर टेनेंट-स्तरीय वर्कलोड के लिए ठोस होता है। प्रति-टेनेंट इंडेक्स छोटे होते हैं, और एक स्कीमा में भारी राइट्स आम तौर पर दूसरों को प्रभावित नहीं करते। ट्रेडऑफ़ ऑपरेशनल ओवरहेड है: नए टेनेंट प्रोविजन करना मतलब एक स्कीमा बनाना, माइग्रेशन्स चलाना, और मॉडल बदलते समय हर स्कीमा को संरेखित रखना।
स्कीमा तब उपयुक्त हैं जब आप tenant_id से अधिक सख्त अलगाव चाहते हैं बिना कई डेटाबेस चलाने की लागत उठाए, या जब आप टेनेंट-स्तर कस्टमाइज़ेशन की उम्मीद करते हैं।
तरीका 3: प्रति टेनेंट अलग डेटाबेस
प्रत्येक टेनेंट के लिए अलग डेटाबेस के साथ, हर ग्राहक को उसका खुद का डेटाबेस (या उसी सर्वर पर उनका अलग डेटाबेस) मिलता है। यह सबसे अलग विकल्प है: अगर किसी टेनेंट का डेटा भ्रष्ट हो जाए या भारी लोड में चले, तो यह दूसरों में फैलने की संभावना कम होती है।
यह नियमन-उन्मुख वातावरण (हेल्थ, फाइनेंस, गवर्नमेंट) या एंटरप्राइज़ ग्राहकों के लिए अच्छा फिट है जो कड़ा अलगाव, कस्टम रिटेंशन नियम, या समर्पित प्रदर्शन की उम्मीद करते हैं।
ऑनबोर्डिंग एक प्रोविजनिंग वर्कफ़्लो बन जाती है। जब नया टेनेंट साइन अप करता है, तो आपकी सिस्टम को डेटाबेस बनाना या क्लोन करना होगा, बेस स्कीमा लागू करना होगा (टेबल्स, इंडेक्स, कंस्ट्रेंट), क्रेडेंशियल्स सुरक्षित रूप से बनाकर स्टोर करने होंगे, और API अनुरोधों को सही डेटाबेस की ओर मार्गदर्शित करना होगा।
यदि आप AppMaster के साथ बना रहे हैं, तो प्रमुख डिजाइन चुनाव यह है कि आप टेनेंट डायरेक्टरी कहाँ रखते हैं (टेनेंट से डेटाबेस कनेक्शन का केंद्रीय मैप) और आप कैसे सुनिश्चित करते हैं कि हर अनुरोध सही कनेक्शन का उपयोग करे।
अपग्रेड्स और माइग्रेशन्स मुख्य ट्रेडऑफ़ हैं। एक स्कीमा बदलाव अब "एक बार चलाएँ" नहीं रहता, बल्कि "हर टेनेंट के लिए चलाएँ" बन जाता है। यह ऑपरेशनल काम और जोखिम बढ़ाता है, इसलिए टीमें अक्सर स्कीमा वर्जनिंग का उपयोग करती हैं और नियंत्रित जॉब्स के रूप में माइग्रेशन्स चलाती हैं जो प्रति-टेनेंट प्रगति ट्रैक करते हैं।
उपसाइड नियंत्रण है। आप बड़े टेनेंट्स को पहले माईग्रेट कर सकते हैं, प्रदर्शन देख सकते हैं, फिर धीरे-धीरे बदलाव रोल आउट कर सकते हैं।
अलग डेटाबेस के साथ रिपोर्टिंग और प्रदर्शन
अलग डेटाबेस सबसे सरल होते हैं समझने में। आकस्मिक क्रॉस-टेनेंट रीड्स बहुत कम संभावित होते हैं, और एक परमिशन गलती सामान्यतः केवल एक टेनेंट को प्रभावित करती है।
प्रदर्शन भी एक ताकत है। भारी क्वेरियाँ, बड़े आयात, या किसी टेनेंट में runaway रिपोर्ट Tenant B को धीमा नहीं करेगी। यह noisy-neighbor से बचाव मजबूत करता है और आपको प्रति-टेनेंट संसाधन ट्यून करने की अनुमति देता है।
ट्रेडऑफ़ रिपोर्टिंग में आता है। ग्लोबल एनालिटिक्स सबसे कठिन होता है क्योंकि डेटा भौतिक रूप से बंटा होता है। व्यवहार में काम करने वाले पैटर्न में प्रमुख इवेंट्स या टेबल्स को केंद्रीय रिपोर्टिंग डेटाबेस में कॉपी करना, इवेंट्स को वेयरहाउस-स्टाइल स्टोर में भेजना, प्रति-टेनेंट रिपोर्ट्स चलाकर परिणामों को एग्रीगेट करना (जब टेनेंट संख्या छोटी हो), और प्रोडक्ट मैट्रिक्स को ग्राहक डेटा से अलग रखना शामिल है।
ऑपरेशनल लागत दूसरा बड़ा कारक है। अधिक डेटाबेस मतलब अधिक बैकअप, अपग्रेड, मॉनिटरिंग और इंसिडेंट रिस्पॉन्स। आप कनेक्शन लिमिट्स भी तेज़ी से हिट कर सकते हैं क्योंकि हर टेनेंट को अपना कनेक्शन पूल चाहिए हो सकता है।
आम गलतियाँ जो डेटा लीक या बाद की परेशानी का कारण बनती हैं
ज़्यादातर मल्टी-टेनेंट मुद्दे "बड़े डिज़ाइन" विफलताएँ नहीं होते। वे छोटे चूकें हैं जो सुरक्षा बग, गंदी रिपोर्टिंग और महंगी सफ़ाई में बढ़ जाती हैं। मल्टी-टेनेंसी तब काम करती है जब टेनेंट अलगाव को आदत बनाया जाए, न कि बाद में जोड़ा गया फीचर।
एक आम लीक है किसी तालिका पर टेनेंट फ़ील्ड भूल जाना, खासकर जॉइन तालिकाओं जैसे user_roles, invoice_items, या tags। सब कुछ ठीक लगता है जब तक कि कोई रिपोर्ट या सर्च उस तालिका के जरिए जॉइन न कर दे और दूसरे टेनेंट की रो खींच ले।
एक और सामान्य समस्या एडमिन डैशबोर्ड हैं जो टेनेंट फ़िल्टर को बाईपास करते हैं। यह अक्सर "सपोर्ट के लिए बस" से शुरू होता है और फिर पुन: उपयोग में आ जाता है। नो-कोड टूल्स यहाँ जोखिम नहीं बदलते: हर क्वेरी, बिज़नेस प्रोसेस, और एंडपॉइंट जो टेनेंट डेटा पढ़ता है उसे एक ही टेनेंट स्कोप चाहिए।
IDs भी आपको काट सकती हैं। अगर आप मानव-फ्रेंडली IDs साझा करते हैं (जैसे order_number = 1001) और मान लेते हैं कि वे वैश्विक रूप से यूनिक हैं, तो सपोर्ट टूल्स और इंटीग्रेशन्स रिकॉर्ड्स को मिश्रित कर देंगे। टेनेंट-स्कोप्ड आइडेंटिफायर्स को आंतरिक प्राथमिक कुंजी से अलग रखें, और लुकअप में टेनेंट संदर्भ शामिल करें।
अंत में, टीमें स्केल होने पर माइग्रेशन्स और बैकअप्स को कम आँकती हैं। जो 10 टेनेंट्स के साथ आसान है, वह 1,000 के साथ धीमा और जोखिम भरा हो सकता है।
त्वरित चेक जो अधिकतर दर्द रोकते हैं:
- हर तालिका पर टेनेंट स्वामित्व स्पष्ट करें, जॉइन तालिकाओं सहित।
- एक टेनेंट स्कोपिंग पैटर्न अपनाएँ और उसे हर जगह पुन: उपयोग करें।
- सुनिश्चित करें कि रिपोर्ट्स और एक्सपोर्ट्स टेनेंट स्कोप के बिना नहीं चल सकते (जब तक कि वे वास्तव में ग्लोबल न हों)।
- APIs और सपोर्ट टूल्स में टेनेंट-अस्पष्ट पहचानकर्ताओं से बचें।
- रिस्टोर और माइग्रेशन चरणों का अभ्यास जल्दी करें, विकास के बाद नहीं।
उदाहरण: एक सपोर्ट एजेंट “invoice 1001” खोजता है और गलत टेनेंट को खींच लेता है क्योंकि लुकअप ने टेनेंट स्कोप छोड़ा। यह एक छोटी बग है जिसका बड़ा प्रभाव हो सकता है।
कमिट करने से पहले एक त्वरित चेकलिस्ट
किसी मल्टी-टेनेंट SaaS डेटा मॉडल को लॉक इन करने से पहले कुछ टेस्ट चलाएँ। लक्ष्य डेटा लीक को जल्दी पकड़ना और पुष्टि करना है कि आपका विकल्प बड़ी तालिकाओं में भी काम करता रहेगा।
एक दिन में किए जा सकने वाले फास्ट चेक
- डेटा अलगाव प्रूफ़: दो टेनेंट (A और B) बनाएं, समान रिकॉर्ड जोड़ें, फिर सत्यापित करें कि हर रीड और अपडेट सक्रिय टेनेंट तक ही सीमित है। केवल UI फ़िल्टर्स पर भरोसा न करें।
- परमिशन ब्रेक टेस्ट: Tenant A उपयोगकर्ता के रूप में लॉग इन करें और केवल रिकॉर्ड ID बदलकर Tenant B का कोई रिकॉर्ड खोलने, संपादित करने, या हटाने की कोशिश करें। अगर कुछ भी सफल होता है, तो इसे रिलीज ब्लॉकर मानें।
- राइट-पाथ सेफ़्टी: पुष्टि करें कि नए रिकॉर्ड हमेशा सही टेनेंट वैल्यू (या सही स्कीमा/डेटाबेस) में ही बनते हैं, भले ही वे बैकग्राउंड जॉब्स, इम्पोर्ट्स, या ऑटोमेशन्स के माध्यम से बनें।
- रिपोर्टिंग परीक्षण: पुष्टि करें कि आप टेनेंट-ओनली रिपोर्ट और "सभी टेनेंट" (आंतरिक स्टाफ के लिए) रिपोर्ट कर सकते हैं, और स्पष्ट नियम हों कि कौन ग्लोबल व्यू देख सकता है।
- प्रदर्शन चेक: अभी ही इंडेक्स रणनीति जोड़ें (खासकर
(tenant_id, created_at)और अन्य सामान्य फ़िल्टर्स के लिए), और जानबूझकर कम से कम एक धीमी क्वेरी मापें ताकि आपको पता हो कि "खराब" कैसा दिखता है।
रिपोर्टिंग टेस्ट को ठोस बनाने के लिए दो प्रश्न चुनें जो आप जानते हों कि आपको चाहिए होंगे (एक टेनेंट-स्कोप्ड, एक ग्लोबल) और उन्हें सैंपल डेटा पर चलाएँ।
-- Tenant-only: last 30 days, one tenant
SELECT count(*)
FROM tickets
WHERE tenant_id = :tenant_id
AND created_at >= now() - interval '30 days';
-- Global (admin): compare tenants
SELECT tenant_id, count(*)
FROM tickets
WHERE created_at >= now() - interval '30 days'
GROUP BY tenant_id;
अगर आप AppMaster में प्रोटोटाइप कर रहे हैं, तो इन चेक्स को अपने Business Process फ्लो (रीड, राइट, डिलीट) में जोड़ें, और Data Designer में दो टेनेंट्स सीड करें। जब ये टेस्ट वास्तविक डेटा वॉल्यूम के साथ पास हों, तब आप आत्मविश्वास के साथ निर्णय ले सकते हैं।
उदाहरण परिदृश्य: पहले ग्राहकों से स्केलिंग तक
एक 20-व्यक्ति की कंपनी अपना कस्टमर पोर्टल लॉन्च कर रही है: इनवॉइस, टिकट, और एक सरल डैशबोर्ड। वे पहले महीने में 10 टेनेंट्स की उम्मीद करते हैं, और अगले साल तक 1,000 तक बढ़ने की योजना है।
शुरू में, सबसे सरल मॉडल आम तौर पर एक ही डेटाबेस होता है जहाँ हर ग्राहक डेटा स्टोर करने वाली तालिका में tenant_id होता है। यह जल्दी बनता है, रिपोर्टिंग आसान रहती है, और डुप्लीकेट सेटअप से बचाता है।
10 टेनेंट्स के साथ, सबसे बड़ा जोखिम प्रदर्शन नहीं होता — यह परमिशन्स होते हैं। एक मिस किया गया फ़िल्टर (उदाहरण के लिए, "list invoices" क्वेरी जिसने tenant_id भूल गया) डेटा लीक कर सकता है। टीम को टेनेंट चेक्स को एक सुसंगत जगह (शेयर्ड बिज़नेस लॉजिक या पुन: उपयोग योग्य API पैटर्न) में लागू करना चाहिए और टेनेंट स्कोपिंग को अनिवार्य मानना चाहिए।
जैसे-जैसे वे 10 से 1,000 टेनेंट्स की ओर बढ़ते हैं, ज़रूरतें बदलती हैं। रिपोर्टिंग भारी हो जाती है, सपोर्ट "किसी टेनेंट के लिए सब कुछ एक्सपोर्ट करें" की मांग करता है, और कुछ बड़े टेनेंट ट्रैफ़िक को डोमिनेट करना शुरू कर देते हैं और साझा तालिकाओं को धीमा कर देते हैं।
एक व्यावहारिक उन्नयन पथ अक्सर कुछ इस तरह दिखता है:
- वही ऐप लॉजिक और परमिशन नियम रखें, लेकिन हाई-वॉल्यूम टेनेंट्स को अलग स्कीमा में मूव करें।
- सबसे बड़े टेनेंट्स (या कंम्प्लायंस क्लाइंट्स) के लिए उन्हें अलग डेटाबेस पर रखें।
- एक साझा रिपोर्टिंग लेयर रखें जो सभी टेनेंट्स से पढ़े, और भारी रिपोर्ट्स को ऑफ-पीक शेड्यूल पर चलाएँ।
आज सुरक्षित रखने वाला सबसे सरल मॉडल चुनें, फिर "कुछ बहुत बड़े टेनेंट्स" की समस्या के लिए माइग्रेशन पथ योजना बनाकर रखें बजाय इसके कि आप पहले दिन ही उसके लिए ऑप्टिमाइज़ करें।
अगले कदम: एक मॉडल चुनें और नो-कोड बैकएंड में इसका प्रोटोटाइप बनाएं
सबसे पहले यह चुनें कि आपको क्या पहले से बचाना है: डेटा अलगाव, ऑपरेशनल सादगी, या टेनेंट-स्तर स्केलिंग। आत्मविश्वास छोटे प्रोटोटाइप और असली परमिशन व रिपोर्टिंग केसों के साथ तोड़ने की कोशिश करने से आता है।
एक साधारण आरंभिक गाइड:
- अगर अधिकांश टेनेंट छोटे हैं और आपको सरल क्रॉस-टेनेंट रिपोर्टिंग चाहिए, तो एक डेटाबेस और हर रो पर
tenant_idके साथ शुरू करें। - अगर आपको अधिक कड़ा अलगाव चाहिए पर एक ही डेटाबेस रखना चाहते हैं, तो प्रति-टेनेंट अलग स्कीमा पर विचार करें।
- अगर टेनेंट हार्ड आइसोलेशन माँगते हैं (अनुपालन, समर्पित बैकअप, noisy-neighbor जोखिम), तो प्रति-टेनेंट अलग डेटाबेस पर विचार करें।
बिल्ड करने से पहले, टेनेंट सीमाओं को साधारण भाषा में लिखें। भूमिकाएँ (owner, admin, agent, viewer) परिभाषित करें, हर एक क्या कर सकता है, और "ग्लोबल" डेटा क्या है (plans, templates, audit logs) यह तय करें। यह भी तय करें कि रिपोर्टिंग कैसे काम करेगी: केवल प्रति-टेनेंट, या आंतरिक स्टाफ के लिए "सभी टेनेंट"।
अगर आप AppMaster का उपयोग कर रहे हैं, तो आप इन पैटर्न्स का तेज़ी से प्रोटोटाइप बना सकते हैं: Data Designer में तालिकाएँ मॉडल करें (सहित tenant_id, यूनिक कंस्ट्रेंट्स, और आपके क्वेरियों पर निर्भर इंडेक्स), फिर Business Process Editor में नियम लागू करें ताकि हर रीड और राइट टेनेंट-स्कोप्ड रहे। एक संदर्भ के रूप में AppMaster appmaster.io पर उपलब्ध है।
एक व्यावहारिक आखिरी टेस्ट: दो टेनेंट बनाएं (A और B), समान उपयोगकर्ता और ऑर्डर्स जोड़ें, और दोनों के लिए वही फ्लो चलाएँ। Tenant A के लिए रिपोर्ट एक्सपोर्ट करने की कोशिश करें, फिर जानबूझकर वही एंडपॉइंट्स में Tenant B के IDs पास करें। आपका प्रोटोटाइप तभी "सुरक्षित-पर्याप्त" है जब वे प्रयास हर बार असफल हों और आपकी प्रमुख रिपोर्ट्स वास्तविक डेटा आकार पर भी तेज़ चलती रहें।
सामान्य प्रश्न
डिफ़ॉल्ट रूप से एक ही डेटाबेस चुनें और हर टेनेंट-स्वामित्व वाली तालिका पर tenant_id रखें अगर आप साधारण संचालन और बार-बार होने वाले क्रॉस-टेनेंट एनालिटिक्स चाहते हैं। जब आपको tenant_id से अधिक कड़ा आइसोलेशन या प्रति-टेनेंट कस्टमाइज़ेशन चाहिए, तो अलग स्कीमा का विकल्प लें। जब अनुपालन या एंटरप्राइज़ जरूरतें कड़ा विभाजन और प्रति-टेनेंट प्रदर्शन नियंत्रण मांगें, तब अलग डेटाबेस चुनें।
टेनेंट स्कोपिंग को बैकएंड में अनिवार्य मानें, UI फ़िल्टर पर भरोसा न करें। टेनेंट-स्वामित्व वाली तालिकाओं पर tenant_id अनिवार्य (NOT NULL) रखें और हमेशा इसे प्रमाणीकृत उपयोगकर्ता के संदर्भ से प्राप्त करें, क्लाइंट-इनपुट पर भरोसा न करें। यदि स्टैक में फिट बैठता है तो PostgreSQL जैसी रॉ-लेवल सुरक्षा जैसी एक सुरक्षा परत जोड़ें, और ऐसे टेस्ट बनाएं जो केवल ID बदलकर दूसरे टेनेंट की रिकॉर्ड पहुँचने की कोशिश करें।
वे इंडेक्स रखें जिनमें tenant_id आपके सामान्य फ़िल्टर के अनुसार पहले आता है, ताकि डेटाबेस सीधे किसी एक टेनेंट के डेटा पर कूद सके। एक सामान्य बेसलाइन है (tenant_id, created_at) को समय-आधारित व्यूज़ के लिए इंडेक्स करना और डैशबोर्ड फ़िल्टर के लिए (tenant_id, status) या (tenant_id, user_id) जोड़ना। यूनिकनेस को भी टेनेंट-स्कोप्ड रखें, जैसे “ईमेल प्रति टेनेंट यूनिक” ताकि टकराव न हो।
अलग स्कीमा चुनने से आकस्मिक क्रॉस-टेनेंट जॉइन कम होते हैं क्योंकि तालिकाएँ अलग नेमस्पेस में रहती हैं, और आप स्कीमा-स्तर पर परमिशन सेट कर सकते हैं। मुख्य नुकसान माइग्रेशन्स हैं: हर स्कीमा में एक ही बदलाव लागू करना पड़ता है, और जैसे-जैसे टेनेंट की संख्या बढ़ती है यह प्रक्रिया जटिल हो जाती है। यह tenant_id की तुलना में अधिक कड़ा आइसोलेशन देता है लेकिन कई डेटाबेस चलाने की लागत नहीं उठाता।
अलग डेटाबेस ब्लास्ट रीडियस (blast radius) को न्यूनतम करता है: प्रदर्शन स्पाइक, मिसकंफिगरेशन या भ्रष्टाचार आमतौर पर एक ही टेनेंट तक सीमित रहता है। लागत ऑपरेशनल ओवरहेड है — प्रोविजनिंग, बैकअप, मॉनिटरिंग और माइग्रेशन्स टेनेंट गणना के साथ बढ़ते हैं। आपको एक विश्वसनीय टेनेंट डायरेक्टरी और अनुरोध रूटिंग की जरूरत होगी ताकि हर API कॉल सही डेटाबेस कनेक्शन का उपयोग करे।
एकल डेटाबेस और tenant_id के साथ क्रॉस-टेनेंट रिपोर्टिंग सबसे आसान होती है क्योंकि ग्लोबल डैशबोर्ड साधारणतः टेनेंट फ़िल्टर के बिना क्वेरी होते हैं। स्कीमा या अलग डेटाबेस के साथ, ग्लोबल एनालिटिक्स आम तौर पर सबसे बेहतर तरीके से किया जाता है किसी साझा रिपोर्टिंग स्टोर में प्रमुख इवेंट्स या समरीज़ को शेड्यूल के जरिए कॉपी करके। नियम सरल रखें: प्रोडक्ट-व्यापी मैट्रिक्स रिपोर्टिंग लेयर में जाएँ, जबकि टेनेंट डेटा अलग रहे।
सपोर्ट टूल में टेनेंट संदर्भ को स्पष्ट रखें और रिकॉर्ड देखने से पहले एक जानबूझकर टेनेंट स्विच आवश्यक करें। अगर आप इम्पर्सोनेशन का उपयोग करते हैं तो लॉग रखें कि किसने कब क्या एक्सेस किया, और इसे समय-सीमित रखें। ऐसे सपोर्ट वर्कफ़्लो से बचें जो केवल रिकॉर्ड ID स्वीकार करते हों बिना टेनेंट संदर्भ के — यही वह तरीका है जिससे “invoice 1001” वाले बग बड़ा लीक बन जाते हैं।
यदि टेनेंट को अलग फ़ील्ड्स या वर्कफ़्लो की ज़रूरत है तो स्कीमा या अलग डेटाबेस इस जोखिम को कम कर सकते हैं कि एक टेनेंट का परिवर्तन दूसरे पर असर डाले। अगर अधिकांश टेनेंट समान हैं तो एक साझा मॉडल रखें और अंतर को फीचर फ्लैग्स या वैकल्पिक फ़ील्ड्स से संभालें। मुख्य लक्ष्य यह है कि साझा और टेनेंट-विशिष्ट अर्थों को स्पष्ट रूप से अलग करें ताकि मॉडल गन्दा न हो।
टेनेंट सीमा को पहले से डिज़ाइन करें: प्रमाणिकरण के बाद टेनेंट संदर्भ कहाँ स्टोर किया जाएगा और कैसे हर रीड/राइट उसे उपयोग करेगा यह तय करें। AppMaster में, आम तौर पर यह अर्थ होता है कि Business Process लॉजिक में प्रमाणीकृत उपयोगकर्ता से tenant_id सेट किया जाए इससे पहले कि आप टेनेंट-स्वामित्व वाली रिकॉर्ड बनाएँ या क्वेरी करें, ताकि एंडपॉइंट इसे भूल न सकें। इसे हर जगह लागू होने वाला पुन: उपयोग योग्य पैटर्न मानें, किसी एक स्क्रीन के लिए अलग समाधान नहीं।
दो समान टेनेंट बनाएं और केवल रिकॉर्ड IDs बदलकर आइसोलेशन को तोड़ने की कोशिश करें — पढ़ने, अपडेट करने और हटाने के दौरान। बैकग्राउंड जॉब्स, इम्पोर्ट और एक्सपोर्ट भी सुनिश्चित करें कि वे सही टेनेंट स्कोप में लिख रहे हैं, क्योंकि ये रास्ते अक्सर अनदेखे रह जाते हैं। साथ ही एक टेनेंट-लेवल रिपोर्ट और एक ग्लोबल एडमिन रिपोर्ट को वास्तविक सैंपल वॉल्यूम के साथ चलाकर प्रदर्शन और एक्सेस नियमों की पुष्टि करें।


