अपग्रेड और ऐड-ऑन के लिए योजनाएँ और एंटाइटलमेंट्स डेटाबेस स्कीमा
एक ऐसा योजनाएँ और एंटाइटलमेंट्स डेटाबेस स्कीमा जो हार्डकोडेड नियमों के बिना साफ़ तालिकाओं और चेक्स के जरिए अपग्रेड, ऐड-ऑन, ट्रायल और रिवोक्स का समर्थन करता है।

क्यों योजनाएँ और फीचर्स जल्दी जटिल हो जाते हैं
प्राइसिंग पेज पर योजनाएँ सरल दिखती हैं: Basic, Pro, Enterprise. असली गड़बड़ी तब शुरू होती है जब आप उन नामों को अपनी ऐप में वास्तविक एक्सेस नियमों में बदलने की कोशिश करते हैं।
हार्डकोडेड फीचर चेक्स (जैसे if plan = Pro then allow X) पहली रिलीज़ के लिए काम करते हैं। फिर प्राइसिंग बदलती है। कोई फीचर Pro से Basic में चला जाता है, कोई नया ऐड-ऑन आता है, या किसी सेल्स डील में कस्टम बंडल शामिल हो जाता है। अचानक वही नियम APIs, UI, मोबाइल ऐप्स और बैकग्राउंड जॉब्स में कॉपी हो चुका होता है। आप एक जगह बदलते हैं और दूसरी भूल जाते हैं। यूज़र नोटिस करते हैं।
दूसरी समस्या समय है। सब्सक्रिप्शन एक स्थिर लेबल नहीं हैं; वे साइकिल के बीच बदलते हैं। कोई आज अपग्रेड करता है, अगले महीने डाउनग्रेड करता है, पॉज़ करता है, या शेष पीढ़ाई के साथ कैंसल करता है। अगर आपका डेटाबेस केवल “वर्तमान प्लान” स्टोर करता है, तो आप टाइमलाइन खो देते हैं और बाद में बुनियादी सवालों का जवाब नहीं दे पाएंगे: मंगलवार को उनके पास क्या एक्सेस था? सपोर्ट ने रिफंड क्यों मंज़ूर किया?
ऐड-ऑन स्थिति और बिगाड़ते हैं क्योंकि वे योजनाओं को काटते हैं। एक ऐड-ऑन अतिरिक्त सीट अनलॉक कर सकता है, किसी सीमा को हटाता है, या किसी विशेष फीचर को सक्षम करता है। लोग इसे किसी भी प्लान पर खरीद सकते हैं, बाद में हटा सकते हैं, या डाउनग्रेड के बाद भी रख सकते हैं। अगर नियम कोड में ही एम्बेड है, तो आपके पास विशेष मामलों का बढ़ता ढेर बन जाएगा।
आमतौर पर ये परिस्थितियाँ सीधी डिजाइन को तोड़ देती हैं:
- मिड-साइकल अपग्रेड: एक्सेस तुरंत बदलना चाहिए, बिलिंग प्रोरेशन अलग नियमों से हो सकता है।
- शेड्यूल्ड डाउनग्रेड: एक्सेस अक्सर पेड अवधि के अंत तक “ऊँचा” बने रहता है।
- ग्रैंडफादरिंग: पुराने ग्राहक किसी फीचर को रखते हैं जिसे नए ग्राहक नहीं पाते।
- कस्टम डील्स: एक अकाउंट को Feature A मिलता है पर Feature B नहीं, जबकि दोनों का प्लान नाम समान है।
- ऑडिट की ज़रूरतें: सपोर्ट, फाइनेंस, या कम्प्लायंस पूछते हैं "किस समय क्या सक्षम था?"
लक्ष्य साधारण है: एक लचीला एक्सेस कंट्रोल मॉडल जो प्राइसिंग के साथ बदले, बिना हर बार बिज़नेस लॉजिक फिर से लिखे। आप एक ऐसी जगह चाहते हैं जहाँ "क्या वे यह कर सकते हैं?" पूछा जा सके और डेटाबेस की ट्रेल जवाब समझा सके।
इस लेख के अंत तक आपके पास एक ऐसा स्कीमा पैटर्न होगा जिसे आप कॉपी कर सकते हैं: योजनाएँ और ऐड-ऑन इनपुट बनते हैं, और एंटाइटलमेंट्स फीचर एक्सेस का सिंगल सोर्स ऑफ ट्रुथ बन जाते हैं। यही दृष्टिकोण नो-कोड बिल्डरों जैसे AppMaster में भी फिट बैठता है, क्योंकि आप नियमों को डाटा में रखकर बैकएंड, वेब ऐप और मोबाइल ऐप से सुसंगत रूप से क्वेरी कर सकते हैं।
प्रमुख शब्द: प्लान, ऐड-ऑन, एंटाइटलमेंट और एक्सेस
कई सब्सक्रिप्शन समस्याएँ शब्दावली की वजह से शुरू होती हैं। अगर हर कोई एक ही शब्द को अलग चीज़ों के लिए इस्तेमाल करे, तो आपका स्कीमा विशेष मामलों में बदल जाएगा।
इन शब्दों को अलग रखना उपयोगी है:
- Plan: वह डिफ़ॉल्ट बंडल जो किसी के सब्सक्राइव करने पर मिलता है (उदाहरण: Basic या Pro). एक प्लान सामान्यतः बेसलाइन लिमिट्स और शामिल फीचर्स सेट करता है।
- Add-on: एक वैकल्पिक खरीद जो बेसलाइन बदलती है (उदाहरण: “अतिरिक्त सीट्स” या “एडवांस्ड रिपोर्टिंग”). ऐड-ऑन को प्लान बदले बिना जोड़ा या हटाया जाना चाहिए।
- Entitlement: अंतिम, गणितीय रूप से निकला "उनके पास अभी क्या है", जो प्लान + ऐड-ऑन + ओवरराइड्स को मिलाकर बनता है। यही आपकी ऐप को क्वेरी करनी चाहिए।
- Permission (या capability): कोई विशिष्ट क्रिया जो कोई कर सकता है (उदाहरण: “डेटा एक्सपोर्ट करें” या “बिलिंग प्रबंधित करें”). Permissions अक्सर रोल + एंटाइटलमेंट पर निर्भर करते हैं।
- Access: वास्तविक दुनिया का परिणाम जब ऐप नियम लागू करता है (स्क्रीन कोई फीचर दिखाती/छिपाती है, API कॉल अनुमति/ब्लॉक होती है, कोई सीमा लागू होती है)।
फीचर फ्लैग्स संबंधित पर अलग हैं। एक feature flag आमतौर पर उत्पाद का एक स्विच होता है जिसे आप कंट्रोल करते हैं (रोलआउट, एक्सपेरिमेंट्स, किसी इनसिडेंट के दौरान फीचर बंद करना)। एक entitlement ग्राहक-विशिष्ट एक्सेस है जो उनकी भुगतान या ग्रांट के आधार पर होता है। समूहों के लिए व्यवहार बदलना हो तो फ्लैग का उपयोग करें; जब एक्सेस बिलिंग, इनवॉइस या कॉन्ट्रैक्ट से मेल खाना चाहिए तो एंटाइटलमेंट्स का उपयोग करें।
स्कोप भी भ्रम का स्रोत है। इन्हें स्पष्ट रखें:
- User: एक व्यक्ति। रोल्स (एडमिन बनाम मेंबर) और व्यक्तिगत सीमाओं के लिए अच्छा।
- Account (customer): भुगतान करने वाली इकाई। बिलिंग जानकारी और सब्सक्रिप्शन ओनरशिप के लिए उपयोगी।
- Workspace (project/team): जहाँ कार्य होता है। कई प्रोडक्ट्स एंटाइटलमेंट्स को यहाँ लागू करते हैं (सीट्स, स्टोरेज, सक्षम मॉड्यूल)।
समय मायने रखता है क्योंकि एक्सेस बदलती है। इसे सीधे मॉडल करें:
- Start and end: एक एंटाइटलमेंट एक विंडो के भीतर सक्रिय हो सकती है (ट्रायल, प्रोमो, वार्षिक कॉन्ट्रैक्ट)।
- Scheduled change: अपग्रेड्स अब शुरू हो सकते हैं; डाउनग्रेड अक्सर अगले नवीनीकरण पर शुरू होते हैं।
- Grace and cancelation: आप भुगतान विफलता के बाद सीमित एक्सेस दे सकते हैं, लेकिन केवल एक स्पष्ट एंड डेट तक।
उदाहरण: एक कंपनी Pro पर है, मध्य-महीने में "Advanced Reporting" जोड़ती है, फिर अगले चक्र में Basic पर लौटने का शेड्यूल करती है। प्लान बाद में बदलता है, ऐड-ऑन अभी शुरू होता है, और एंटाइटलमेंट लेयर वही एक जगह रहती है जहाँ प्रश्न पूछा जाता है: "क्या इस वर्कस्पेस को आज एडवांस्ड रिपोर्ट्स उपयोग करने की अनुमति है?"
योजनाओं और फीचर्स के लिए एक सरल कोर स्कीमा
एक अच्छा स्कीमा छोटा और साफ़ शुरु होता है: जो आप बेचते हैं (प्लान और ऐड-ऑन) उसे उन चीज़ों से अलग रखें जो लोग कर सकते हैं (फीचर्स)। अगर आप इन दोनों विचारों को साफ़ रखेंगे तो अपग्रेड और नए ऐड-ऑन डेटा बदलाव बनेंगे, कोड के री-राइट नहीं।
यहाँ एक व्यावहारिक कोर सेट ऑफ़ टेबल्स है जो अधिकांश सब्सक्रिप्शन प्रोडक्ट्स के लिए काम करता है:
- products: बिकने योग्य चीज़ (Base plan, Team plan, Extra seats add-on, Priority support add-on)।
- plans: वैकल्पिक, अगर आप चाहें कि प्लान विशेष प्रकार का प्रोडक्ट हो जिसमें प्लान-केवल फ़ील्ड हों (बिलिंग इंटरवल, सार्वजनिक डिस्प्ले ऑर्डर)। कई टीमें प्लान्स को
productsके भीतर रखती हैं औरproduct_typeकॉलम इस्तेमाल करती हैं। - features: कैपेबिलिटीज़ की कैटलॉग (API access, max projects, export, SSO, SMS credits)।
- product_features (या
plan_featuresअगर आप प्लान अलग करते हैं): एक जॉइन टेबल जो बताती है कि किस प्रोडक्ट में कौन सा फीचर आता है, आम तौर पर किसी वैल्यू के साथ।
यही जॉइन टेबल अधिकतर पावर रखती है। फीचर्स अक्सर सिर्फ ऑन/ऑफ नहीं होते। एक प्लान में max_projects = 10 हो सकता है, जबकि एक ऐड-ऑन +5 जोड़ सकता है। तो product_features को कम से कम ये सपोर्ट करना चाहिए:
feature_value(नंबर, टेक्स्ट, JSON, या अलग कॉलम)value_type(boolean, integer, enum, json)grant_mode(replace vs add), ताकि एक ऐड-ऑन बेस लिमिट को ओवरराइट करने के बजाय "+5 सीट्स" दे सके
ऐड-ऑन को भी प्रोडक्ट्स की तरह मॉडल करें। केवल फर्क खरीदने के तरीके का होगा। एक बेस प्लान प्रोडक्ट "एक बार" होने जैसा है, जबकि एक ऐड-ऑन मात्रा की अनुमति दे सकता है। पर दोनों फीचर्स को समान तरीके से मैप करते हैं। इससे कोड में "अगर ऐड-ऑन X है तो Y सक्षम करें" जैसे स्पेशल केस्स से बचाव होता है।
फीचर्स को डाटा में रखें, कोड कंसटैंट्स में नहीं। अगर आप फीचर चेक्स कई सर्विसेज में हार्डकोड करते हैं, तो आप अंततः मिसमैच भेज देंगे (वेब कहता है हाँ, मोबाइल कहता है नहीं, बैकएंड अलग कहता है)। जब फीचर्स डेटाबेस में होते हैं, ऐप एक सुसंगत प्रश्न पूछ सकता है और आप पंक्तियों को एडिट करके बदलाव रोलआउट कर सकते हैं।
नामकरण अपेक्षा से ज्यादा मायने रखता है। स्थिर पहचानकर्ता प्रयोग करें जो कभी नहीं बदलें, भले ही मार्केटिंग नाम बदल जाएँ:
feature_keyजैसेmax_projects,sso,priority_supportproduct_codeजैसेplan_starter_monthly,addon_extra_seats
डिस्प्ले लेबल अलग रखें (feature_name, product_name). अगर आप AppMaster के Data Designer के साथ PostgreSQL उपयोग कर रहे हैं, तो इन कीज़ को यूनिक फ़ील्ड के रूप में रखना तुरंत लाभ देता है: आप सुरक्षित रूप से रिजनरेट कर सकते हैं और इंटीग्रेशन व रिपोर्टिंग स्थिर रख सकते हैं।
एंटाइटलमेंट लेयर: "क्या वे कर सकते हैं?" पूछने की एक जगह
اکثر سبسکرپشن سسٹمز اس وقت مشکل میں پڑتے ہیں جب "انہوں نے کیا خریدا" ایک جگہ ذخیرہ ہو، مگر "وہ کیا کر سکتے ہیں" پانچ مختلف کوڈ راستوں میں حساب کیا جائے۔ حل ہے ایک एंटाइटलमेंट लेयर: एक सिंगल टेबल (या व्यू) जो किसी सब्जेक्ट के लिए किसी पॉइंट इन टाइम पर प्रभावी एक्सेस दर्शाती है।
अगर आप एक ऐसा स्कीमा चाहते हैं जो अपग्रेड, डाउनग्रेड, ट्रायल और वन-ऑफ ग्रांट्स को संभाल सके, तो यह लेयर वह हिस्सा है जो सब कुछ अनुमानित बनाता है।
एक व्यावहारिक एंटाइटलमेंट्स टेबल
हर पंक्ति को एक क्लेम के रूप में सोचें: "यह सब्जेक्ट इस फीचर तक इस वैल्यू के साथ इस समय से इस समय तक इस स्रोत से एक्सेस रखता है।" एक आम स्वरूप ऐसा दिखता है:
- subject_type (उदा., "account", "user", "org") और subject_id
- feature_id
- value (उस फीचर का प्रभावी मान)
- source (कहां से आया: "direct", "plan", "addon", "default")
- starts_at और ends_at (nullable ends_at का मतलब जारी एक्सेस)
आप value को कुछ तरीकों से लागू कर सकते हैं: एक टेक्स्ट/JSON कॉलम प्लस value_type, या अलग कॉलम्स जैसे value_bool, value_int, value_text. इसे सरल और क्वेरी-फ्रेंडली रखें।
उन वैल्यू टाइप्स की जो अधिकांश उत्पादों को कवर करते हैं
फ़ीचर्स हमेशा ऑन/ऑफ नहीं होते। ये वैल्यू टाइप्स वास्तविक बिलिंग और एक्सेस कंट्रोल ज़रूरतों को अक्सर कवर करते हैं:
- Boolean: सक्षम/अक्षम ("can_export" = true)
- Quota number: एक सीमा ("seats" = 10, "api_calls" = 100000)
- Tier level: एक रैंक ("support_tier" = 2)
- String: मोड या वेरिएंट ("data_retention" = "90_days")
प्रीसिडेंस: संघर्ष कैसे सुलझे
संघर्ष सामान्य हैं। एक यूज़र किसी ऐसे प्लान पर हो सकता है जो 5 सीट्स देता है, एक ऐड-ऑन खरीदता है जो 10 और देता है, और सपोर्ट से मैनुअल ग्रांट भी मिल सकता है।
एक स्पष्ट नियम सेट करें और हर जगह उसे लागू रखें:
- Direct grant प्लान को ओवरराइड करता है
- फिर add-ons
- फिर defaults
सरल तरीका यह है कि आप सभी कैंडिडेट पंक्तियाँ स्टोर करें (प्लान-डेराइव्ड, ऐड-ऑन-डेराइव्ड, डायरेक्ट) और एक फाइनल "विनर" per subject_id + feature_id निकालें स्रोत प्रीसिडेंस के आधार पर, फिर newest starts_at।
यहाँ एक ठोस परिदृश्य है: एक ग्राहक आज अपना प्लान डाउनग्रेड करता है, पर उसने एक ऐड-ऑन खरीदा हुआ है जो महीने के अंत तक चलता है। starts_at/ends_at वाले एंटाइटलमेंट्स के साथ, डाउनग्रेड प्लान-आधारित फीचर्स के लिए तुरंत प्रभावी हो जाता है, जबकि ऐड-ऑन फीचर अपने ends_at तक सक्रिय रहता है। आपकी ऐप "क्या वे कर सकते हैं?" का उत्तर एक ही क्वेरी से दे सकती है, अलग-थलग लॉजिक की जरूरत नहीं।
सब्सक्रिप्शन्स, आइटम्स और समय-सीमित एक्सेस
आपका प्लान कैटलॉग (प्लान्स, ऐड-ऑन, फीचर्स) "क्या है" बताता है। सब्सक्रिप्शन बताते हैं "किसके पास क्या है, और कब।" अगर आप इन्हें अलग रखते हैं, तो अपग्रेड और कैंसलेशन डरावने नहीं रहते।
एक व्यावहारिक पैटर्न है: एक अकाउंट पर एक सब्सक्रिप्शन और उसके अंतर्गत कई सब्सक्रिप्शन आइटम्स (एक बेस प्लान के लिए और शून्य या अधिक ऐड-ऑन के लिए)। यह आपको समय के साथ होने वाले बदलाव रिकॉर्ड करने की साफ़ जगह देता है बिना एक्सेस नियमों को फिर से लिखे।
खरीद टाइमलाइन मॉडल करने के लिए कोर टेबल्स
आप दो साधारण टेबल्स के साथ इसे सरल रख सकते हैं जो क्वेरी करने में आसान हैं:
- subscriptions: id, account_id, status (active, trialing, canceled, past_due), started_at, current_period_start, current_period_end, canceled_at (nullable)
- subscription_items: id, subscription_id, item_type (plan, addon), plan_id/addon_id, quantity, started_at, ends_at (nullable), source (stripe, manual, promo)
एक सामान्य विवरण: हर आइटम को उसकी अपनी तारीखों के साथ स्टोर करें। इस तरह आप किसी ऐड-ऑन को केवल 30 दिनों के लिए दे सकते हैं, या किसी प्लान को पेड अवधि के अंत तक चलने दे सकते हैं भले ही ग्राहक नवीनीकरण रद्द कर दे।
प्रोरेशन और बिलिंग को एक्सेस लॉजिक से दूर रखें
प्रोरेशन, इनवॉइसेस और पेमेंट रिट्राइज बिलिंग की समस्याएँ हैं। फीचर एक्सेस एंटाइटलमेंट की समस्या है। इनवॉइस लाइनों से "एक्सेस कैलकुलेट" करने की कोशिश मत करें।
इसके बजाय, बिलिंग इवेंट्स सब्सक्रिप्शन रिकॉर्ड्स को अपडेट करें (उदा., current_period_end बढ़ाएं, नया subscription_item row बनाएं, या ends_at सेट करें)। आपकी ऐप तब सब्सक्रिप्शन टाइमलाइन (और बाद में एंटाइटलमेंट लेयर) से एक्सेस सवालों का जवाब देगी, बिलिंग गणित से नहीं।
शेड्यूल्ड बदलाव बिना आश्चर्य के
अपग्रेड और डाउनग्रेड अक्सर किसी विशेष समय पर प्रभावी होते हैं:
- सब्सक्रिप्शन्स पर pending_plan_id और change_at जोड़ें ताकि एक शेड्यूल्ड प्लान बदलाव का एक सिंगल पॉइंट हो।
- या यदि आपको हिस्ट्री और कई भविष्य के बदलाव चाहिए तो subscription_changes टेबल का उपयोग करें (subscription_id, effective_at, from_plan_id, to_plan_id, reason)।
यह यादृच्छिक कोड भागों में "डाउनग्रेड पीरियड एंड पर होते हैं" जैसे नियमों को हार्डकोड करने से बचाता है। शेड्यूल डेटा है।
ट्रायल कहाँ फिट बैठते हैं
ट्रायल समय-सीमित एक्सेस ही हैं जिनका स्रोत अलग होता है। दो साफ विकल्प:
- ट्रायल को सब्सक्रिप्शन स्टेटस (trialing) के रूप में रखें जिसमें trial_start/trial_end तारीखें हों।
- या ट्रायल को स्टार्टेड/एंडेड एंटाइटलमेंट आइटम्स बनाकर source = trial रखें।
अगर आप AppMaster में बना रहे हैं, तो ये टेबल्स Data Designer में साफ़मैप हो जाती हैं, और तारीखें "अब क्या सक्रिय है" क्वेरी करना बिना स्पेशल केस के आसान बना देती हैं।
चरण-दर-चरण: पैटर्न लागू करें
एक अच्छा स्कीमा इस वादे से शुरू होता है: फीचर लॉजिक डाटा में रहता है, कोड पाथ्स में बिखरा नहीं। आपकी ऐप को एक ही प्रश्न पूछना चाहिए—"अभी प्रभावी एंटाइटलमेंट्स क्या हैं?"—और साफ़ उत्तर मिलना चाहिए।
1) स्थिर कीज़ के साथ फीचर्स परिभाषित करें
एक feature टेबल बनाएं जिसमें एक स्थिर, पढ़ने योग्य key हो जिसे आप कभी नहीं बदलेंगे (भले ही UI लेबल बदले)। अच्छे कीज़ दिखते हैं: export_csv, api_calls_per_month, या seats।
एक प्रकार जोड़ें ताकि सिस्टम जान सके वैल्यू को कैसे ट्रीट करना है: boolean (on/off) बनाम numeric (limits/quotas)। साधारण और सुसंगत रखें।
2) प्लान और ऐड-ऑन को एंटाइटलमेंट्स से मैप करें
अब आपको दो सत्य स्रोत चाहिए: एक कि प्लान में क्या शामिल है, और दूसरा कि हर ऐड-ऑन क्या ग्रांट करता है।
एक सरल अनुक्रम यह है:
- सभी फीचर्स को एक
featureटेबल में रखें, स्थिर कीज़ और वैल्यू टाइप के साथ। planऔरplan_entitlementबनाएं जहाँ हर पंक्ति एक फीचर वैल्यू ग्रांट करती है (उदा.seats = 5,export_csv = true).addonऔरaddon_entitlementबनाएं जो अतिरिक्त वैल्यूज़ ग्रांट करते हैं (उदा.seats + 10,api_calls_per_month + 50000, याpriority_support = true).- यह तय करें कि वैल्यूज़ को कैसे मिलाया जाए: booleans आमतौर पर OR का उपयोग करते हैं, संख्यात्मक सीमाएँ अक्सर MAX (ऊँचा जीतता) का उपयोग करती हैं, और सीट जैसी मात्रा अक्सर SUM से संयुक्त होती है।
- एंटाइटलमेंट्स कब शुरू और खत्म होते हैं यह रिकॉर्ड करें ताकि अपग्रेड, कैंसलेशन और प्रोरेशन एक्सेस चेक्स को न तोड़ें।
अगर आप AppMaster में बना रहे हैं, तो आप इन टेबल्स को Data Designer में मॉडल कर सकते हैं और कॉम्बाइन नियमों को एक छोटा "policy" टेबल या enum के रूप में Business Process लॉजिक में रख सकते हैं।
3) “प्रभावी एंटाइटलमेंट्स” तैयार करें
आपके पास दो विकल्प हैं: पढ़ते समय (compute on read) हर बार क्वेरी करके मर्ज करें, या जब कुछ बदले तो एक कैश्ड स्नैपशॉट जनरेट करें। अधिकांश ऐप्स के लिए स्नैपशॉट्स तर्कसंगत और लोड के तहत तेज़ होते हैं।
एक आम तरीका account_entitlement टेबल है जो प्रति फीचर फाइनल परिणाम स्टोर करती है, साथ में valid_from और valid_to।
4) एक्सेस को एक चेक से लागू करें
कई स्क्रीन, एंडपॉइंट और बैकग्राउंड जॉब्स में नियम फैलाने से बचें। ऐप को एक फ़ंक्शन दें जो प्रभावी एंटाइटलमेंट्स पढ़े और फैसला करे।
can(account_id, feature_key, needed_value=1):
ent = get_effective_entitlement(account_id, feature_key, now)
if ent.type == "bool": return ent.value == true
if ent.type == "number": return ent.value >= needed_value
एक बार जब सब कुछ can(...) कॉल करे, तो अपग्रेड और ऐड-ऑन डाटा अपडेट बन जाते हैं, कोड री-राइट नहीं।
उदाहरण परिदृश्य: बिना सरप्राइज़ के अपग्रेड प्लस ऐड-ऑन
एक 6 व्यक्ति की सपोर्ट टीम Starter प्लान पर है। Starter में 3 एजेंट सीट्स और महीने के 1,000 SMS संदेश हैं। मध्य-महीने वे 6 एजेंट तक बढ़ते हैं और एक अतिरिक्त 5,000 SMS पैक चाहते हैं। आप चाहते हैं कि यह बिना "अगर प्लान = Pro तो..." जैसे स्पेशल केस के काम करे।
दिन 1: वे Starter पर शुरू करते हैं
आप खाते के लिए एक subscription बनाते हैं जिसमें एक बिलिंग पीरियड होता है (उदा., 1 Jan से 31 Jan)। फिर आप प्लान के लिए एक subscription_item जोड़ते हैं।
चेकआउट पर (या रात में चलने वाली नौकरी द्वारा) आप उस अवधि के लिए एंटाइटलमेंट ग्रांट लिखते हैं:
entitlement_grant:agent_seats, मान3, शुरुआत1 Jan, अंत31 Janentitlement_grant:sms_messages, मान1000, शुरुआत1 Jan, अंत31 Jan
आपकी ऐप कभी नहीं पूछती "वे किस प्लान पर हैं?" बल्कि पूछती है "उनका प्रभावी एंटाइटलमेंट अभी क्या है?" और उसे seats = 3, SMS = 1000 मिलता है।
दिन 15: Pro में अपग्रेड और उसी दिन SMS पैक जोड़ना
15 Jan को वे Pro में अपग्रेड करते हैं (जिसमें 10 एजेंट सीट्स और 2,000 SMS शामिल हैं)। आप पुराने ग्रांट्स को एडिट नहीं करते। आप नई रिकॉर्ड्स जोड़ते हैं:
- पुराने प्लान आइटम को बंद करें:
subscription_item(Starter) का end15 Janसेट करें - नया प्लान आइटम बनाएं:
subscription_item(Pro) start15 Jan, end31 Jan - नया ऐड-ऑन आइटम जोड़ें:
subscription_item(SMS Pack 5000) start15 Jan, end31 Jan
फिर उसी अवधि के लिए ग्रांट्स जोड़े जाते हैं:
entitlement_grant:agent_seats, मान10, start15 Jan, end31 Janentitlement_grant:sms_messages, मान2000, start15 Jan, end31 Janentitlement_grant:sms_messages, मान5000, start15 Jan, end31 Jan
15 Jan को क्या होता है?
- Seats: प्रभावी सीट्स 10 हो जाती हैं (आप सीट्स के लिए नियम जैसे "ऊँचा मान लें" चुनते हैं). वे उसी दिन 3 और एजेंट जोड़ सकते हैं।
- SMS: प्रभावी SMS शेष अवधि के लिए 7,000 हो जाती है (आप संदेश पैक्स के लिए "जोड़" का नियम चुनते हैं)।
किसी भी मौजूदा उपयोग को "मूव" करने की ज़रूरत नहीं है। आपकी उपयोग तालिका संदेशों की गिनती रखती रहती है; एंटाइटलमेंट चेक बस उपयोग की तुलना वर्तमान प्रभावी सीमा से करता है।
दिन 25: डाउनग्रेड शेड्यूल करें, अवधि समाप्ति तक एक्सेस रखें
25 Jan को वे Feb 1 से Starter पर लौटने का शेड्यूल करते हैं। आप Jan के ग्रांट्स को छूते नहीं हैं। आप अगले पीरियड के लिए भविष्य के आइटम बनाते हैं:
subscription_item(Starter) start1 Feb, end28 Feb- 1 Feb से कोई SMS पैक आइटम नहीं
परिणाम: वे Pro सीट्स और SMS पैक को 31 Jan तक रखते हैं। 1 Feb को उनकी प्रभावी सीट्स 3 हो जाती हैं और SMS नए पीरियड के लिए Starter लिमिट पर वापस आ जाता है। यह सोचने में आसान है और AppMaster जैसे नो-कोड वर्कफ़्लो में साफ़ मैप हो जाता है: तारीखें बदलने से नई पंक्तियाँ बनती हैं और एंटाइटलमेंट क्वेरी वही रहती है।
सामान्य गलतियाँ और जाल
अधिकांश सब्सक्रिप्शन बग बिलिंग बग नहीं होते। वे एक्सेस बग होते हैं जो प्रोडक्ट में बिखरे लॉजिक की वजह से होते हैं। एक plans and entitlements डेटाबेस स्कीमा को सबसे तेजी से तोड़ने का तरीका है "क्या वे कर सकते हैं?" का जवाब पाँच अलग जगहों पर देना।
एक क्लासिक फ़ेलियर UI, API और बैकग्राउंड जॉब्स में नियमों को हार्डकोड करना है। UI एक बटन छिपा देता है, API भूल जाता है एंडपॉइंट ब्लॉक करे, और नाइटली जॉब अभी भी चलता है क्योंकि वह कुछ और चेक करता है। आप "यह कभी-कभी काम करता है" जैसी रिपोर्ट्स के साथ फंस जाते हैं जिन्हें दोहराना मुश्किल होता है।
एक और जाल plan_id चेक्स का उपयोग करना है बजाय फीचर चेक्स के। शुरुआत में यह सरल लगता है (Plan A एक्स्पोर्ट कर सकता है, Plan B नहीं), पर यह तब टूट जाता है जब आप ऐड-ऑन जोड़ते हैं, किसी ग्राहक को ग्रैंडफादर करते हैं, फ्री ट्रायल देते हैं, या एंटरप्राइज़ अपवाद आता है। अगर आप कभी कहते हैं "यदि प्लान Pro है तो अनुमति दें...", तो आप एक भूल-भरी भूल बना रहे हैं जिसे बनाए रखना मुश्किल होगा।
समय और रद्द करने के एज-केसेस
एक और समस्या तब आती है जब आप केवल एक बूलियन जैसे has_export = true स्टोर करते हैं और कभी तारीखें नहीं जोड़ते। कैंसलेशन, रिफंड, चार्जबैक और मिड-साइकल डाउनग्रेड्स सब टाइम-बाउंड होते हैं। starts_at और ends_at के बिना आप गलती से स्थायी एक्सेस दे देंगे, या बहुत जल्दी एक्सेस हटा देंगे।
इसे टालने के लिए सरल चेक:
- हर एंटाइटलमेंट ग्रांट का एक स्रोत होना चाहिए (plan, add-on, manual override) और एक समय रेंज।
- हर एक्सेस निर्णय "अब start और end के बीच है" का उपयोग करे (null end तारीखों के लिए स्पष्ट नियम के साथ)।
- बैकग्राउंड जॉब्स रनटाइम पर एंटाइटलमेंट्स को फिर से चेक करें, न कि कल की स्थिति मानें।
बिलिंग और एक्सेस को मिलाकर न रखें
टीमें तब समस्या में पड़ती हैं जब बिलिंग रिकॉर्ड्स और एक्सेस नियमों को एक ही टेबल में मिलाती हैं। बिलिंग को इनवॉइस, टैक्स, प्रोरेशन, प्रोवाइडर IDs, और रिट्राई स्टेट्स चाहिए। एक्सेस को स्पष्ट फीचर कीज़ और समय विंडोज चाहिए। जब ये उलझ जाते हैं, तो एक बिलिंग माइग्रेशन प्रोडक्ट आउटेज बन सकती है।
अंत में, कई सिस्टम ऑडिट ट्रेल स्किप कर देते हैं। जब कोई उपयोगकर्ता पूछे "मुझे एक्स्पोर्ट क्यों मिल रहा है?", तो आपको उत्तर चाहिए जैसे: "Add-on X द्वारा 2026-01-01 से 2026-02-01 तक सक्षम किया गया" या "सपोर्ट ने मैन्युअली ग्रांट किया, टिकट 1842." इसके बिना सपोर्ट और इंजीनियरिंग अनुमान लगाते हैं।
अगर आप AppMaster में बना रहे हैं, तो अपने Data Designer मॉडल में ऑडिट फ़ील्ड रखें और "क्या वे कर सकते हैं?" चेक को एक सिंगल Business Process बनाएं ताकि वेब, मोबाइल और शेड्यूल्ड फ्लोज़ सब वही नियम उपयोग करें।
भेजने से पहले त्वरित चेकलिस्ट
शिप करने से पहले एक आखिरी पास वास्तविक सवालों के साथ करें, न कि सिद्धांतों के साथ। लक्ष्य यह है कि एक्सेस समझने योग्य, टेस्ट करने योग्य और बदलाव-मैत्रीपूर्ण हो।
वास्तविकता जाँचने वाले प्रश्न
एक उपयोगकर्ता और एक फीचर चुनें, फिर परिणाम को ऐसे समझाएँ जैसे आप सपोर्ट या फाइनेंस को बता रहे हों। अगर आप केवल कह सकें "वे Pro पर हैं" (या बदतर, "कोड ऐसा कहता है"), तो पहला मिड-साइकल अपग्रेड या वन-ऑफ़ डील में दर्द होगा।
यह त्वरित चेकलिस्ट उपयोग करें:
- क्या आप डेटा अकेले (सब्सक्रिप्शन आइटम्स, ऐड-ऑन, ओवरराइड्स, और समय विंडोज) देखकर जवाब दे सकते हैं "किसलिए इस उपयोगकर्ता के पास एक्सेस है?" बिना एप्लिकेशन कोड पढ़े।
- क्या सभी एक्सेस चेक्स स्थिर फीचर कीज़ (जैसे
feature.export_csv) पर आधारित हैं न कि प्लान नामों पर (जैसे "Starter" या "Business")। प्लान नाम बदलते हैं; फीचर कीज़ नहीं बदलनी चाहिए। - क्या एंटाइटलमेंट्स के पास स्पष्ट start और end समय हैं, जिसमें ट्रायल, ग्रेस पीरियड और शेड्यूल्ड कैंसलेशन शामिल हैं। अगर समय गायब है तो डाउनग्रेड तर्क बन जाते हैं।
- क्या आप किसी एक ग्राहक के लिए ओवरराइड रिकॉर्ड के जरिए एक्सेस दे या हटा सकते हैं बिना लॉजिक में शाखाएँ जोड़े। यही तरीका है "इस महीने उन्हें 10 अतिरिक्त सीट्स दें" बिना कस्टम कोड के।
- क्या आप कुछ सैंपल रोस से अपग्रेड और डाउनग्रेड का परीक्षण कर सकते हैं और अनुमानित परिणाम मिलते हैं। अगर इसे सिमुलेट करने के लिए जटिल स्क्रिप्ट चाहिए, तो आपका मॉडल बहुत अमूर्त है।
एक व्यावहारिक परीक्षण: तीन उपयोगकर्ता बनाएं (नया, मिड-महीने अपग्रेड किया हुआ, रद्द किया हुआ) और एक ऐड-ऑन (जैसे "अतिरिक्त सीट्स" या "एडवांस्ड रिपोर्ट्स")। फिर हर एक के लिए अपनी एक्सेस क्वेरी चलाएँ। अगर परिणाम स्पष्ट और समझाने योग्य हैं, तो आप तैयार हैं।
अगर आप AppMaster जैसे टूल का उपयोग कर रहे हैं, तो वही नियम रखें: एक जगह (एक क्वेरी या एक Business Process) को ही "क्या वे कर सकते हैं?" का जिम्मेदार बनायें ताकि हर वेब और मोबाइल स्क्रीन वही उत्तर पाए।
अगले कदम: अपग्रेड्स को बनाए रखना आसान बनाएं
अपग्रेड्स को सुसंगत रखने का सबसे अच्छा तरीका है कि आप जितना सोचते हैं उससे छोटा शुरू करें। कुछ चुनिंदा फीचर्स चुनें जो वास्तविक मूल्य लाते हों (5-10 पर्याप्त हैं) और एक एंटाइटलमेंट क्वेरी/फ़ंक्शन बनाएं जो एक ही प्रश्न का उत्तर दे: "क्या यह अकाउंट अभी X कर सकता है?" अगर आप यह एक जगह नहीं बता पा रहे तो अपग्रेड हमेशा जोखिम भरे रहेंगे।
जब वह एक चेक काम कर जाए, तो अपग्रेड पाथ्स को प्रोडक्ट बिहेवियर की तरह ट्रीट करें, केवल बिलिंग बिहेवियर नहीं। अजीब एज-केसेस पकड़ने का सबसे तेज़ तरीका यह है कि वास्तविक ग्राहक मूव्स पर आधारित कुछ एक्सेस टेस्ट लिखें।
कुछ व्यावहारिक अगले कदम जो तुरंत लाभ देते हैं:
- एक न्यूनतम फीचर कॅटलॉग परिभाषित करें और हर प्लान को स्पष्ट एंटाइटलमेंट्स से मैप करें।
- ऐड-ऑन को अलग आइटम्स के रूप में जोड़ें जो एंटाइटलमेंट्स को ग्रांट या बढ़ाते हैं, बजाय उन्हें प्लान नियमों में पका देने के।
- आम पाथ्स के लिए 5-10 एक्सेस टेस्ट लिखें (मिड-साइकल अपग्रेड, नवीनीकरण पर डाउनग्रेड शेड्यूल, ऐड-ऑन जोड़ना फिर हटाना, ट्रायल से पेड, ग्रेस पीरियड)।
- प्राइसिंग बदलावों को सिर्फ डेटा बनाएं: प्लान रोस, फीचर मैपिंग्स, और एंटाइटलमेंट ग्रांट्स को अपडेट करें, एप्लिकेशन कोड नहीं।
- आदत बनाएं: हर नए प्लान या ऐड-ऑन के साथ कम से कम एक नया परीक्षण जुड़ा हो जो साबित करे कि एक्सेस अपेक्षित तरीके से काम कर रहा है।
अगर आप नो-कोड बैकएंड का उपयोग कर रहे हैं, तब भी आप इस पैटर्न को साफ़ तरीके से मॉडल कर सकते हैं। AppMaster में Data Designer कोर टेबल्स (plans, features, subscriptions, subscription items, entitlements) के लिए अच्छा है। फिर Business Process Editor में एक्सेस निर्णय के फ्लो (सक्रिय एंटाइटलमेंट्स लोड करना, समय विंडोज़ लागू करना, allow/deny लौटाना) रखें ताकि आप एंडपॉइंट्स पर बिखरे हुए चेक्स को हाथ से कोड न करें।
लाभ तब दिखता है जब अगली बार प्राइसिंग बदलती है। आप नियमों को फिर से लिखने की बजाय डेटा एडिट करते हैं: एक फीचर Pro से ऐड-ऑन में चले जाता है, एंटाइटलमेंट अवधि बदलती है, या एक लेगसी प्लान अपने पुराने ग्रांट रखता है। आपकी एक्सेस लॉजिक स्थिर रहती है, और अपग्रेड्स एक नियंत्रित अपडेट बन जाते हैं, कोड स्प्रिंट नहीं।
यदि आप अपना स्कीमा जल्दी वैलिडेट करना चाहते हैं, तो एक अपग्रेड और एक ऐड-ऑन को end-to-end मॉडल करके शुरू करें, फिर उन एक्सेस टेस्ट्स को चलाएँ इससे पहले कि आप कुछ और जोड़ें।


