আপগ্রেড ও অ্যাড-অনের জন্য পরিকল্পনা ও অধিকার ডাটাবেস স্কিমা
আপগ্রেড, অ্যাড-অন, ট্রায়াল ও রিভোকেশন সামলাতে সক্ষম একটি পরিকল্পনা ও অধিকার ডাটাবেস স্কিমা—হার্ডকোডেড নিয়ম নয়, স্পষ্ট টেবিল ও চেক ব্যবহার করে।

কেন পরিকল্পনা ও ফিচার দ্রুত জটিল হয়ে যায়
প্রাইসিং পেজে পরিকল্পনা দেখায় সহজ: Basic, Pro, Enterprise। কিন্তু ওই নামগুলো বাস্তবে অ্যাপের ভেতরে অ্যাক্সেস নিয়মে বদলে দেওয়ার সময়ই জটিলতা শুরু হয়।
ফিচার চেকগুলো হার্ডকোড করা (যেমন if plan = Pro then allow X) প্রথম রিলিজে কাজ করে। তারপর প্রাইসিং বদলায়, কোনো ফিচার Pro থেকে Basic-এ চলে আসে, নতুন কোনো অ্যাড-অন আসে, বা সেলস ডিলে কাস্টম বন্ডল থাকে। হঠাৎ একই নিয়ম API, UI, মোবাইল অ্যাপ এবং ব্যাকগ্রাউন্ড জবে ছড়িয়ে পরে। আপনি এক জায়গা পরিবর্তন করেন আর অন্যটি ভুলে যান। ব্যবহারকারী লক্ষ্য করে।
দ্বিতীয় সমস্যা হলো সময়। সাবস্ক্রিপশন একটি স্থির লেবেল নয়; এটি চক্রের মধ্যেই বদলে যায়। কেউ আজ আপগ্রেড করতে পারে, পরের মাসে ডাউনগ্রেড, বিরতি দিতে পারে, বা পেইড সময় বাকি থাকা সত্ত্বেও বাতিল করে দিতে পারে। যদি আপনার ডাটাবেস কেবল “বর্তমান প্ল্যান” রাখে, আপনি টাইমলাইন হারিয়ে ফেলেন এবং পরে মৌলিক প্রশ্নের উত্তর দিতে পারবেন না: গত মঙ্গলবার তাদের কী ছিল? কেন সাপোর্ট রিফান্ড অনুমোদন করেছে?
অ্যাড-অনগুলো আরও খারাপ করে কারণ এগুলো প্ল্যানের উপর ছড়ায়। একটা অ্যাড-অন অতিরিক্ত সীট আনলক করতে পারে, কোনো লিমিট তুলে দিতে পারে, বা নির্দিষ্ট ফিচার চালু করতে পারে। মানুষ যে কোন প্ল্যানে এটি কিনতে পারে, পরে সরাতে পারে, অথবা ডাউনগ্রেডের পরে রেখে দিতে পারে। যদি নিয়ম কোডে এম্বেড করা থাকে, তাহলে বিশেষ কেসের পরোয়া বাড়বে।
নিচে সাধারণ পরিস্থিতিগুলো আছে যা অলপ সূক্ষ্ম ডিজাইন ভাঙে:
- মধ্য-চক্র আপগ্রেড: অ্যাক্সেস তৎক্ষণাত বদলে যাওয়া উচিত, বিলিং প্রোরেশন আলাদা নিয়মে হতে পারে।
- নির্ধারিত ডাউনগ্রেড: পেইড পিরিয়ড শেষ হওয়া পর্যন্ত অ্যাক্সেস “উচ্চ” থাকতে পারে।
- গ্র্যান্ডফাদারিং: পুরোনো গ্রাহকরা এমন ফিচার পেতে পারে যা নতুনরা পায় না।
- কাস্টম ডিল: এক অ্যাকাউন্ট পায় ফিচার A কিন্তু B পায় না, যদিও একই প্ল্যান নাম আছে।
- অডিট প্রয়োজন: সাপোর্ট, ফাইন্যান্স বা কমপ্লায়েন্স জিজ্ঞেস করে “কবে এবং কী সক্রিয় ছিল?”
লক্ষ্যটি সহজ: এমন একটি নমনীয় অ্যাক্সেস কন্ট্রোল মডেল যা প্রাইসিং পরিবর্তনের সঙ্গে সঙ্গতি রাখে, প্রতি বার বিজনেস লজিক পুনরায় লিখতে না হয়। আপনি এক জায়গা চাইবেন যেখান থেকে প্রশ্ন করা যাবে “তারা কি এটা করতে পারে?” এবং ডাটাবেস ট্রেইল থাকবে যা উত্তর ব্যাখ্যা করবে।
এই প্রবন্ধের শেষে আপনি এমন একটি স্কিমা প্যাটার্ন পাবেন যা অনুলিপি করা যাবে: পরিকল্পনা এবং অ্যাড-অন ইনপুট হয়ে উঠবে, আর অধিকার (entitlements) হবে ফিচার অ্যাক্সেসের সিঙ্গেল সোর্স অফ ট্রুথ। একই পদ্ধতি AppMaster মত নো-কোড বিল্ডারের ক্ষেত্রেও যায়, কারণ নিয়মগুলো ডাটাতে রেখে ব্যাকএন্ড, ওয়েব ও মোবাইল থেকে ধারাবাহিকভাবে কোয়েরি করা যাবে।
মূল শব্দ: প্ল্যান, অ্যাড-অন, অধিকার, এবং অ্যাক্সেস
অনেক সাবস্ক্রিপশন সমস্যা একটি ভোকাবুলারি সমস্যাই থেকে শুরু হয়। সবাই একই শব্দ দিয়ে ভিন্ন জিনিস বোঝালে, আপনার স্কিমা বিশেষ কেসে পরিণত হয়।
স্কিমা-তে আলাদা রাখা উচিত এমন শব্দগুলো:
- Plan: সাবস্ক্রাইব করলে ডিফল্ট বান্ডল (উদাহরণ: Basic বা Pro)। সাধারণত প্ল্যান বেসলাইন লিমিট এবং ইনক্লুডেড ফিচার নির্ধারণ করে।
- Add-on: ঐচ্ছিক ক্রয় যা বেসলাইন বদলে দেয় (উদাহরণ: “extra seats” বা “advanced reporting”)। অ্যাড-অনগুলো প্ল্যান বদলাতেই সংযুক্ত অথবা সরানো যেতে পারে।
- Entitlement: চূড়ান্ত, গণনা করা “তাদের এখন যা আছে”, যা প্ল্যান + অ্যাড-অন + ওভাররাইড মিলিয়ে পাওয়া হয়। এটাই আপনার অ্যাপকে কোয়েরি করতে হবে।
- Permission (বা capability): নির্দিষ্ট কোনো অ্যাকশন (উদাহরণ: “export data” বা “manage billing”)। পারমিশনগুলো প্রায়ই ভূমিকা (role) এবং অধিকার মিলিয়ে নির্ধারিত হয়।
- Access: বাস্তব ফলাফল যখন অ্যাপ নিয়ম প্রয়োগ করে (স্ক্রিন দেখায় বা লুকায়, API কল অনুমতি পায় বা ব্লক হয়, লিমিট প্রয়োগ হয়)।
ফিচার ফ্ল্যাগগুলো সম্পর্কিত কিন্তু আলাদা। একটি feature flag সাধারণত একটি প্রোডাক্ট সুইচ যা আপনি কন্ট্রোল করেন (রোলআউট, এক্সপেরিমেন্ট, বা কোনো ঘটনার সময় ফিচার বন্ধ করা)। একটি entitlement গ্রাহক-নির্দিষ্ট অ্যাক্সেস যা তারা কী পরিশোধ করেছে বা আপনি কী দিয়েছেন তার ওপর ভিত্তি করে। গ্রুপের জন্য আচরণ বদলাতে ফিচার ফ্ল্যাগ ব্যবহার করুন; যখন অ্যাক্সেস বিলিং, ইনভয়েস বা কন্ট্রাক্টের সঙ্গে মিলতে হবে তখন entitlement ব্যবহার করুন।
স্কোপ আরেকটি বিভ্রান্তির উৎস। স্পষ্ট রাখুন:
- User: একজন ব্যক্তি। ভূমিকার জন্য (অ্যাডমিন বনাম মেম্বার) এবং ব্যক্তিগত লিমিটের জন্য ভাল।
- Account (customer): যে অর্থ প্রদান করে। বিলিং তথ্য ও সাবস্ক্রিপশন মালিকানার জন্য ভাল।
- Workspace (project/team): কাজ যেখানে হয়। অনেক পণ্য এখানে entitlements প্রয়োগ করে (সীটস, স্টোরেজ, সক্রিয় মডিউল)।
সময় গুরুত্বপূর্ণ কারণ অ্যাক্সেস বদলায়। সরাসরি মডেল করুন:
- Start and end: একটি entitlement শুধুমাত্র একটি উইন্ডোর মধ্যে সক্রিয় থাকতে পারে (ট্রায়াল, প্রোমো, বার্ষিক চুক্তি)।
- Scheduled change: আপগ্রেড এখন থেকেই শুরু হতে পারে; ডাউনগ্রেড সাধারণত পরবর্তী রিনিউয়ালে শুরু হয়।
- Grace and cancelation: পেমেন্ট ফেইল হলে সীমিত অ্যাক্সেস দিতে পারেন, তবে একটি স্পষ্ট শেষ তারিখ থাকা উচিত।
উদাহরণ: একটি কোম্পানি Pro-তে আছে, মাঝামাঝি সময়ে “Advanced Reporting” অ্যাড করে, পরে পরবর্তী সাইকলেই Basic-এ ডাউনগ্রেড নির্ধারণ করে। প্ল্যান পরে বদলে যায়, অ্যাড-অন এখন থেকেই শুরু করে, এবং entitlement লেয়ারই একমাত্র স্থান যেখানে প্রশ্ন করা হয়: “আজকে এই ওয়ার্কস্পেস কি advanced reports ব্যবহার করতে পারে?”
পরিকল্পনা ও ফিচারের জন্য সহজ কোর স্কিমা
একটি ভালো স্কিমা ছোট থেকে শুরু করে: যা আপনি বিক্রি করেন (প্ল্যান ও অ্যাড-অন) আলাদা রাখুন এবং যা মানুষ করতে পারে (ফিচার) আলাদা রাখুন। এই দুই ধারণা পরিষ্কার রাখলে, আপগ্রেড ও নতুন অ্যাড-অনগুলো ডাটা পরিবর্তন হয়ে যাবে, কোড পুনর্লিখন হবে না।
নিচে এমন কিছু প্র্যাকটিক্যাল কোর টেবিল আছে যা অধিকাংশ সাবস্ক্রিপশন প্রোডাক্টে কাজ করে:
products: বিক্রয়ের বস্তু (Base plan, Team plan, Extra seats add-on, Priority support add-on)।plans: ঐচ্ছিক, যদি আপনি প্ল্যানকেproductsথেকে আলাদা টাইপ হিসেবে রাখতে চান (বিলিং ইন্টার্ভাল, পাবলিক ডিসপ্লে অর্ডার সহ)। অনেক টিমproducts-এর মধ্যে প্ল্যান রেখেproduct_typeকলাম ব্যবহার করে।features: কিপটালগ (API access, max projects, export, SSO, SMS credits)।product_features(বাplan_featuresযদি আপনি আলাদা করেন): কোন প্রোডাক্ট কোন ফিচার দেয় তা বলার জন্য একটি জয়েন টেবিল, সাধারণত একটি value সহ।
এই জয়েন টেবিলেই বড় সুবিধা থাকে। ফিচারগুলো সাধারণত কেবল অন/অফ নয়। একটি প্ল্যান max_projects = 10 থাকতে পারে, আর একটি অ্যাড-অন +5 যোগ করতে পারে। তাই product_features কমপক্ষে সহায়তা করা উচিত:
feature_value(নাম্বার, টেক্সট, JSON, বা আলাদা কলাম)value_type(boolean, integer, enum, json)grant_mode(replace বনাম add), যাতে একটি অ্যাড-অন বেস লিমিট ওভাররাইট না করে বরং “+5 seats” করতে পারে
অ্যাড-অনকেও প্রোডাক্ট হিসেবে মডেল করুন। একমাত্র পার্থক্য হচ্ছে কীভাবে সেগুলো ক্রয় করা হয়। একটি বেস প্ল্যান প্রোডাক্ট সাধারণত “একটি মাত্র” হয়, যখন একটি অ্যাড-অন প্রোডাক্টের পরিমাণ গ্রহণ করতে পারে। কিন্তু দুটোই একইভাবে ফিচার ম্যাপে ম্যাপ করে। এতে কোডে "if add-on X then enable feature Y" মত স্পেশাল কেস এড়ানো যায়।
ফিচারগুলো ডাটার মধ্যে থাকা উচিত, কোড কনস্ট্যান্ট নয়। যদি আপনি বহু সার্ভিসে ফিচার চেক হার্ডকোড করেন, শেষ পর্যন্ত মিল নাও হতে পারে (ওয়েব বলে আছে, মোবাইল বলে নেই, ব্যাকএন্ড ভিন্ন আচরণ করে)। যখন ফিচার ডাটাবেসে থাকে, অ্যাপ একটি ধারাবাহিক প্রশ্ন করে এবং সারি সম্পাদনা করে পরিবর্তন আসবে।
নামকরণ প্রত্যাশার চেয়ে বেশি গুরুত্বপূর্ণ। স্থির আইডেন্টিফায়ার ব্যবহার করুন যা কখনও বদলাবে না, এমনকি মার্কেটিং নাম বদলে গেলেও:
feature_keyযেমনmax_projects,sso,priority_supportproduct_codeযেমনplan_starter_monthly,addon_extra_seats
ডিসপ্লে লেবেল আলাদা রাখুন (feature_name, product_name)। AppMaster-এর Data Designer ও PostgreSQL ব্যবহার করলে, এই কীগুলোকে ইউনিক রাখা উপকারি: ইন্টিগ্রেশন ও রিপোর্টিং সেফ থাকতে পারে যখন আপনি পুনরায় জেনারেট করবেন।
অধিকার লেয়ার: এক জায়গা থেকে “ওরা কি পারে?” জিজ্ঞাসা করা
অধিকাংশ সাবস্ক্রিপশন সিস্টেম তখনই বিকৃত হয় যখন “তারা কী কিনেছে” এক জায়গায় রাখা থাকে কিন্তু “তারা কী করতে পারে” পাঁচটি আলাদা কোডপাথে গণনা করা হয়। সমাধান হচ্ছে entitlement লেয়ার: একটি একক টেবিল (বা ভিউ) যা একটি সাবজেক্টের কার্যকর অ্যাক্সেসকে একটি সময় পয়েন্টে উপস্থাপন করে।
আপনি যদি এমন একটি স্কিমা চান যা আপগ্রেড, ডাউনগ্রেড, ট্রায়াল এবং এক-অফ গ্রান্ট সহ টিকে থাকে, এই লেয়ারই সব predictable করে তোলে।
একটি ব্যবহারিক entitlements টেবিল
প্রতিটি সারিকে একটি ক্লেইম হিসেবে ভাবুন: “এই সাবজেক্ট এই ফিচারে এই মান সহ এই সময় থেকে এই সময় পর্যন্ত এই সোর্স থেকে অ্যাক্সেস পায়।” একটি সাধারণ ফর্ম এভাবে থাকে:
- 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
সরল একটি উপায় হলো সব candidate সারি (plan-derived, add-on-derived, direct) রেখে ফিচার আইডি অনুযায়ী সোর্স প্রাধান্য ও সর্বাধিকতার ভিত্তিতে একটি “উইনার” নির্ণয় করা।
একটি কংক্রিট দৃশ্য: কাস্টমার আজ প্ল্যান ডাউনগ্রেড করে, কিন্তু আগে থেকেই পেইড একটি অ্যাড-অন মাস শেষে পর্যন্ত বৈধ। starts_at/ends_at সহ entitlements থাকলে, প্ল্যান-ভিত্তিক ফিচার তৎক্ষণাত কমে যেতে পারে, আর অ্যাড-অনটি its ends_at পর্যন্ত সক্রিয় থাকে। আপনার অ্যাপ একক প্রশ্নে “তারা কি পারে?” উত্তর দিতে পারবে, বিশেষ-কেস লজিকে না গিয়ে।
সাবস্ক্রিপশন, আইটেম, এবং সময় সীমিত অ্যাক্সেস
আপনার প্ল্যান ক্যাটালগ (প্ল্যান, অ্যাড-অন, ফিচার) হলো “কি।” সাবস্ক্রিপশন হলো “কে কি পেয়েছে, এবং কখন।” যদি আপনি এ দুই আলাদা রাখেন, আপগ্রেড এবং বাতিল ভয়ানক হওয়া বন্ধ হয়।
একটি ব্যবহারিক প্যাটার্ন: এক অ্যাকাউন্টে একটি সাবস্ক্রিপশন, এবং তার নিচে বহু subscription items (একটা বেস প্ল্যানের জন্য, এবং শূন্য বা আরো অ্যাড-অন)। এতে টাইমলাইনের পরিবর্তন রেকর্ড করা সহজ হয় এবং অ্যাক্সেস নিয়ম পুনরায় লেখার প্রয়োজন পড়ে না।
ক্রয়ের টাইমলাইন মডেল করার কোর টেবিল
সহজ রাখতে দুইটি টেবিল যথেষ্ট:
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)
একটি সাধারণ বিবরণ: প্রতিটি আইটেমকে নিজস্ব তারিখসহ স্টোর করুন। এভাবে আপনি একটি অ্যাড-অন ৩০ দিনের জন্য প্রশিক্ষণ দিতে পারেন, অথবা কেউ রিনিউয়াল বাতিল করলে পেইড পিরিয়ড শেষ পর্যন্ত প্ল্যান চলে যেতে দিন।
প্রোরেশন ও বিলিংকে অ্যাক্সেস লজিক থেকে আলাদা রাখুন
প্রোরেশন, ইনভয়েস ও পেমেন্ট রিট্রাই সবই বিলিংয়ের বিষয়। ফিচার অ্যাক্সেস একটি entitlement সমস্যা। ইনভয়েস লাইনের থেকে অ্যাক্সেস হিসাব করার চেষ্টা করবেন না।
বদলে, বিলিং ইভেন্টগুলো subscription রেকর্ড আপডেট করুক (উদাহরণ: current_period_end বাড়ানো, নতুন subscription_item তৈরি করা, অথবা ends_at সেট করা)। আপনার অ্যাপ তখন বিলিং গণিত থেকে নয় বরং সাবস্ক্রিপশন টাইমলাইন (এবং পরে entitlement লেয়ার) থেকে অ্যাক্সেস প্রশ্নের উত্তর দেবে।
নির্ধারিত পরিবর্তনগুলো অবাঞ্ছিত আচরণ ছাড়াই
আপগ্রেড ও ডাউনগ্রেড প্রায়ই একটি নির্দিষ্ট সময়ে কার্যকর হয়:
- সাবস্ক্রিপশনে pending_plan_id এবং change_at যোগ করুন একক নির্ধারিত প্ল্যান পরিবর্তনের জন্য।
- অথবা যদি ইতিহাস ও ভবিষ্যত একাধিক পরিবর্তন দরকার হয়, একটি subscription_changes টেবিল ব্যবহার করুন (subscription_id, effective_at, from_plan_id, to_plan_id, reason)।
এটি র্যান্ডম কোড অংশে “ডাউনগ্রেড পিরিয়ড শেষে হয়” মত নিয়ম হার্ডকোড হওয়া ঠেকায়। সময়সূচি হল ডাটা।
ট্রায়াল কোথায় বসে
ট্রায়াল হল সময়-সীমাবদ্ধ অ্যাক্সেস যা ভিন্ন সোর্স দিয়ে চিহ্নিত করা যায়। দুটি পরিষ্কার বিকল্প:
- ট্রায়ালকে সাবস্ক্রিপশনের একটি স্ট্যাটাস হিসেবে ট্রিট করুন (trialing) সাথে trial_start/trial_end।
- অথবা ট্রায়াল-গ্রান্টেড আইটেম/entitlements তৈরি করুন started_at/ends_at এবং source = trial সহ।
AppMaster-এ তৈরি করলে এই টেবিলগুলো Data Designer-এ সুন্দরভাবে বসে এবং তারিখগুলো “এখন কি সক্রিয়” সহজ ভাবে কোয়েরি করা সম্ভব করে তোলে।
ধাপে ধাপে: প্যাটার্ন ইমপ্লিমেন্ট করা
ভালো স্কিমা একটি অঙ্গীকার থেকে শুরু করে: ফিচার লজিক ডাটাতে থাকবে, বিভিন্ন কোডপাথে ছড়িয়ে থাকবে না। আপনার অ্যাপকে একটি প্রশ্ন করতে হবে — “এখন কার্যকর entitlements কী?” — এবং একটি স্পষ্ট উত্তর পেতে হবে।
1) স্থিতিশীল কী দিয়ে ফিচার সংজ্ঞায়িত করুন
একটি feature টেবিল তৈরি করুন যেখানে একটি স্থির, মানব-পঠযোগ্য কী থাকবে যা আপনি কখনো বদলাবেন না (UI লেবেল বদলেও)। ভাল কী দেখতে যেমন export_csv, api_calls_per_month, বা seats।
টাইপ যোগ করুন যাতে সিস্টেম জানে মানটি কিভাবে ট্রীট করবে: boolean (on/off) বনাম numeric (লিমিট/কোটা)। নিরপেক্ষ ও নির্ভরযোগ্য রাখুন।
2) প্ল্যান ও অ্যাড-অনকে অধিকারগুলোর সাথে ম্যাপ করুন
এখন আপনার দুইটি সোর্স দরকার: প্ল্যান কী দেয়, এবং প্রতিটি অ্যাড-অন কী গ্রান্ট করে।
সরল, ব্যবহারিক ধারা:
- সব ফিচার একটি
featureটেবিলে রাখুন স্থিতিশীল কী ও ভ্যালু টাইপ সহ। - প্রতিটি প্ল্যান ও প্ল্যান_entitlement তৈরি করুন যেখানে প্রতিটি সারি একটি ফিচার ভ্যালু গ্রান্ট করে (উদা:
seats = 5,export_csv = true)। - প্রতিটি অ্যাড-অন ও addon_entitlement তৈরি করুন যা অতিরিক্ত মান দেয় (উদা:
seats + 10,api_calls_per_month + 50000, বাpriority_support = true)। - মানগুলো কিভাবে কম্বাইন করবেন তা নির্ধারণ করুন: boolean-এ সাধারণত OR, নমেরিক লিমিটে MAX (উচ্চতর জয়ী), সীটস-ধরনের ক্ষেত্রে SUM প্রয়োগ করা যায়।
- যখন entitlements শুরু এবং শেষ করে তা রেকর্ড করুন যাতে আপগ্রেড, বাতিল ও প্রোরেশন অ্যাক্সেস চেক ভেঙে না ফেলে।
AppMaster-এ আপনি এই টেবিলগুলো Data Designer-এ মডেল করতে পারেন এবং কম্বাইন নিয়মগুলো একটি ছোট “policy” টেবিল বা enum হিসেবে Business Process লজিকে রাখতে পারেন।
3) “কার্যকর entitlements” উৎপন্ন করুন
আপনার কাছে দুটি বিকল্প আছে: প্রতি রিডে গণনা করা (প্রতিবার কোয়েরি করে সব মিলিয়ে হিসাব করা) অথবা যখন কিছু বদলে যায় তখন ক্যাশড স্ন্যাপশট জেনারেট করা। বেশিরভাগ অ্যাপের জন্য স্ন্যাপশটগুলো বোঝা সহজ ও লোডে দ্রুত।
সাধারণ পদ্ধতি হলো একটি account_entitlement টেবিল রাখা যা প্রতিটি ফিচারের চূড়ান্ত ফলাফল সংরক্ষণ করে, সাথে valid_from ও valid_to।
4) একক চেক দিয়ে অ্যাক্সেস প্রয়োগ করুন
নিয়মগুলো স্ক্রিন, এন্ডপয়েন্ট ও ব্যাকগ্রাউন্ড জবে না ছড়িয়ে দিন। অ্যাপ কোডে একটি ফাংশন রাখুন যা কার্যকর entitlements পড়ে সিদ্ধান্ত নেয়।
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 চান। আপনি চান এটি বিশেষ-কেস কোড ছাড়া কাজ করুক।
দিন 1: তারা Starter-এ শুরু করে
আপনি account-এর জন্য একটি subscription তৈরি করেন একটি বিলিং পিরিয়ড সহ (উদা: Jan 1 থেকে Jan 31)। তারপর একটি subscription_item প্ল্যানের জন্য যোগ করেন।
চেকআউট অথবা রাতের ব্যাচে আপনি ওই পিরিয়ডের জন্য entitlement গ্রান্ট লেখেন:
entitlement_grant:agent_seats, value3, startJan 1, endJan 31entitlement_grant:sms_messages, value1000, startJan 1, endJan 31
আপনার অ্যাপ কখনই জিজ্ঞেস করে না “তারা কোন প্ল্যানে আছে?” বরং জিজ্ঞাসা করে “এদের কার্যকর entitlement এখন কী?” এবং সীট = 3, SMS = 1000 পায়।
দিন 15: Pro-তে আপগ্রেড, একই দিন SMS প্যাক যোগ
Jan 15-এ তারা Pro-তে আপগ্রেড করে (10 এজেন্ট সীট এবং 2,000 SMS)। আপনি পুরনো গ্রান্টগুলো পরিবর্তন করছেন না—নতুন রেকর্ড যোগ করছেন:
- পুরোনো প্ল্যান আইটেম বন্ধ করুন:
subscription_item(Starter) ends =Jan 15 - নতুন প্ল্যান আইটেম তৈরি করুন:
subscription_item(Pro) starts =Jan 15, ends =Jan 31 - একটি অ্যাড-অন আইটেম যোগ করুন:
subscription_item(SMS Pack 5000) starts =Jan 15, ends =Jan 31
তারপর একই পিরিয়ডের জন্য গ্রান্ট যুক্ত করে দিতে হবে:
entitlement_grant:agent_seats, value10, startJan 15, endJan 31entitlement_grant:sms_messages, value2000, startJan 15, endJan 31entitlement_grant:sms_messages, value5000, startJan 15, endJan 31
Jan 15-এ কি ঘটে?
- Seats: কার্যকর সীট 10 হয় (আপনি সীটসমূহের জন্য "max" বা অন্য নীতি বেছে নিতে পারেন)। তারা ঐ দিন 3 অতিরিক্ত এজেন্ট যোগ করতে পারে।
- SMS: কার্যকর SMS বাকি পিরিয়ডের জন্য 7,000 হয় (মেসেজ প্যাকগুলোর জন্য আপনি "sum additive grants" ব্যবহার করেন)।
কোনও বিদ্যমান ইউজেজ মুভ করার দরকার নেই। আপনার ইউজেজ টেবিল মেসেজ গননা চালায়; entitlement চেক কেবল গননা করে যে সেটা বর্তমান কার্যকর লিমিটের তুলনায় কোথায় আছে।
দিন 25: ডাউনগ্রেড নির্ধারণ, পিরিয়ড শেষ পর্যন্ত অ্যাক্সেস রেখে
Jan 25-এ তারা Feb 1 থেকে Starter-এ ডাউনগ্রেড নির্ধারণ করে। আপনি Jan গ্রান্টগুলো স্পর্শ করেন না। আপনি পরের পিরিয়ডের জন্য ভবিষ্যৎ আইটেম (অথবা ভবিষ্যৎ গ্রান্ট) তৈরি করেন:
subscription_item(Starter) startFeb 1, endFeb 28- Feb 1 থেকে কোনো SMS pack আইটেম নেই
ফলাফল: তারা Jan 31 পর্যন্ত Pro সীট ও SMS প্যাক উপভোগ করে। Feb 1-এ তাদের কার্যকর সীট আবার 3 হবে এবং নতুন পিরিয়ডে Starter লিমিট ফিরে আসবে। এটি বোধগম্য এবং AppMaster-এ নো-কোড ওয়ার্কফ্লো হিসেবে সহজ: কেবল তারিখ বদলানো নতুন সারি তৈরি করে, আর entitlement কোয়েরি একই থাকে।
সাধারণ ভুল ও ফাঁদ
বেশিরভাগ সাবস্ক্রিপশন বাগ বিলিং বাগ নয়—এগুলো অ্যাক্সেস বাগ যা প্রোডাক্ট জুড়ে লজিক ছড়িয়ে পড়ার ফলে হয়। দ্রুত ভেঙে দেয়া স্কিমা হলো যেখানে “তারা কি ব্যবহার করতে পারে?” পাঁচটি আলাদা স্থানে উত্তর পাওয়া যায়।
একটি ক্লাসিক ব্যর্থতা হলো UI, API ও ব্যাকগ্রাউন্ড জবে নিয়মগুলো হার্ডকোড করা। UI বাটন লুকায়, API ভুলে ব্লক করে, আর নাইটলি জব অন্য কিছু চেক করে চলতে থাকে। ফলে "কখনো কাজ করে, কখনো না" রিপোর্ট দেখা যায় যা পুনরুত্পাদন করা কঠিন।
আরেকটি ফাঁদ হলো plan_id চেক ব্যবহার করা। প্রথমে এটা সহজ মনে হয় (Plan A export করতে পারে, Plan B পারে না), কিন্তু অ্যাড-অন, গ্র্যান্ডফাদার, ফ্রি ট্রায়াল বা এন্টারপ্রাইজ এক্সেপশন এলে এটি ভেঙে যায়। যদি আপনি কখনো বলেন "if plan is Pro then allow...", আপনি একটি মরপ্যাচ গঠন করছেন যা মেইনটেইন করতে হবে।
সময় ও বাতিলকরণ এজ-কেস
অ্যাক্সেস "আটকে" পড়ে যখন আপনি কেবল একটি বুলিয়ান যেমন has_export = true সংরক্ষণ করেন এবং কখনো তারিখ যুক্ত করেন না। বাতিল, রিফান্ড, চার্জব্যাক ও মধ্য-চক্র ডাউনগ্রেড—সবকিছুই টাইম-বাউন্ড দরকার। starts_at ও ends_at ছাড়া আপনি ভুল করে স্থায়ী অ্যাক্সেস দেবেন, অথবা খুব তাড়াতাড়ি অ্যাক্সেস কেটে দেবেন।
এড়িয়ে চলার সহজ চেক:
- প্রতিটি entitlement grant-এ সোর্স (plan, add-on, manual override) এবং একটি টাইম রেঞ্জ থাকতে হবে।
- প্রতিটি অ্যাক্সেস সিদ্ধান্তে "now between start and end" ব্যবহার করুন (null end date এর জন্য স্পষ্ট নিয়ম রাখুন)।
- ব্যাকগ্রাউন্ড জবগুলো রান-টাইমে entitlements পুনরায় চেক করবে, গতকালকার স্টেট ধরে নিয়ে চলবে না।
বিলিং ও অ্যাক্সেস মিশ্রিত করবেন না
টিমগুলো বিলিং রেকর্ড ও অ্যাক্সেস নিয়ম একই টেবিলে মিশিয়ে দুর্দশায় পড়ে। বিলিং-এ ইনভয়েস, ট্যাক্স, প্রোরেশন, প্রোভাইডার আইডি এবং রিট্রাই স্টেট দরকার। অ্যাক্সেসে দরকার স্পষ্ট ফিচার কী এবং সময় উইন্ডো। যখন দুটো জটিলভাবে মিলেমিশে থাকে, একটি বিলিং মাইগ্রেশন প্রোডাকশন আউটেজে পরিণত হতে পারে।
অবশেষে, অনেক সিস্টেম অডিট ট্রেইল বাদ দেয়। যখন ব্যবহারকারী জিজ্ঞেস করে “আমি কেন export করতে পারছি?”, আপনাকে বলা উচিত: “Add-on X দ্বারা 2026-01-01 থেকে 2026-02-01 পর্যন্ত সক্রিয়” অথবা “সাপোর্ট দ্বারা ম্যানুয়ালি গ্রান্ট করা, টিকেট 1842।” এ ছাড়া সাপোর্ট ও ইঞ্জিনিয়ারিং অনুমান করে যাবে।
AppMaster-এ এটি নির্মাণ করলে, Data Designer মডেলে অডিট ফিল্ড রাখুন এবং “can they?” চেককে একটি একক Business Process হিসাবে রেখে দিন যাতে ওয়েব, মোবাইল ও শিডিউল্ড ফ্লো একই লজিক ব্যবহার করে।
চালানোর আগে দ্রুত চেকলিস্ট
আপনার স্কিমা চালানোর আগে বাস্তব প্রশ্ন নিয়ে একবার দেখুন। লক্ষ্য হলো অ্যাক্সেস ব্যাখ্যাযোগ্য, টেস্টেবল এবং পরিবর্তন-বন্ধুত্বপূর্ণ থাকা।
বাস্তবতার প্রশ্নগুলো
একজন ব্যবহারকারী এবং একটি ফিচার বেছে নিন, তারপর সাপোর্ট বা ফাইন্যান্সকে যেভাবে বোঝাবেন তেমনি রূপে ফলাফল ব্যাখ্যা করার চেষ্টা করুন। যদি আপনি কেবল বলতে পারেন “তারা Pro-এ আছে” (অথবা খারাপ হলে “কোড বলছে”) তাহলে যখন কেউ মধ্য-চক্র আপগ্রেড করবে বা এক-অফ ডিল পাবে আপনি কষ্ট পেতে পারেন।
হালকা চেকলিস্ট:
- আপনি কি "কেন এই ব্যবহারকারীর অ্যাক্সেস আছে?" ডাটা (subscription items, add-ons, overrides, time windows) দেখে ব্যাখ্যা করতে পারেন, অ্যাপ কোড না পড়ে?
- সব অ্যাক্সেস চেক কি স্থিতিশীল feature কী (যেমন
feature.export_csv) ভিত্তিক, প্ল্যান নামের পরিবর্তে? প্ল্যান নাম বদলাতে পারে; feature কী বদলানো উচিত নয়। - Entitlements কি স্পষ্ট start ও end টাইম সহ আছে, ট্রায়াল, গ্রেস পিরিয়ড এবং নির্ধারিত বাতিলকরণ সহ? সময় না থাকলে ডাউনগ্রেড বিতর্কে পরিণত হয়।
- আপনি কি একটি কাস্টম ওভাররাইড রেকর্ড দিয়ে এক গ্রাহকের জন্য অ্যাক্সেস দাড় করাতে বা সরাতে পারবেন, লজিক শাখা না করে? এভাবেই "এই মাসে 10 অতিরিক্ত সীট দিন" জাতীয় অনুরোধগুলো হ্যান্ডেল করা যায়।
- আপনি কি একটি আপগ্রেড এবং ডাউনগ্রেডকে কয়েকটি স্যাম্পল সারি দিয়ে টেস্ট করে ভবিষ্যদ্বাণীকৃত ফলাফল পেতে পারবেন? যদি একটি জটিল স্ক্রিপ্ট লাগে সিমুলেট করার জন্য, আপনার মডেল খুব অপ্রকাশ্য।
একটি ব্যবহারিক পরীক্ষা: তিনটি ব্যবহারকারী তৈরি করুন (নতুন, মধ্য-চক্র আপগ্রেড করা, বাতিল করা) এবং একটি অ্যাড-অন (যেমন "extra seats" বা "advanced reports")। তারপর প্রতিটির জন্য আপনার অ্যাক্সেস কোয়েরি চালান। যদি ফলাফল সহজ ও ব্যাখ্যাযোগ্য হয়, আপনি প্রস্তুত।
AppMaster-এ থাকলে একই নিয়ম রাখুন: একটি জায়গা (কোয়েরি বা Business Process) যেটা "can they?" জরুরি সিদ্ধান্ত নেয়, যাতে প্রতিটি ওয়েব ও মোবাইল স্ক্রিন একই উত্তর পায়।
পরবর্তী ধাপ: আপগ্রেডগুলো রক্ষণাবেক্ষণ সহজ করা
আপগ্রেডগুলোকে বাঁচিয়ে রাখার সর্বোত্তম উপায় হচ্ছে ছোট থেকে শুরু করা। কেবল কয়েকটি প্রধান ফিচার বেছে নিন (5-10 যথেষ্ট) এবং একটি entitlement কোয়েরি বা ফাংশন তৈরি করুন যা একটি প্রশ্নের উত্তর দেয়: “এই অ্যাকাউন্ট কি X এখন করতে পারে?” যদি এটি এক জায়গায় উত্তর না দেয়, আপগ্রেড সবসময় ঝুঁকিপূর্ণ থাকবে।
একই চেক কাজ করলে, আপগ্রেড প্যাথগুলোকে প্রোডাক্ট আচরণ হিসেবে বিবেচনা করুন, শুধুমাত্র বিলিং আচরণ হিসেবে না। অস্বাভাবিক এজ-কেসগুলো ধরার দ্রুত উপায় হল গ্রাহক-চলফের উপর ভিত্তি করে কয়েকটি অ্যাক্সেস টেস্ট লেখা।
কিছু তাত্ত্বিক পরবর্তী ধাপ যা দ্রুত ফল দেয়:
- একটি মিনিমাল ফিচার ক্যাটালগ সংজ্ঞায়িত করুন এবং প্রতিটি প্ল্যানকে পরিষ্কার entitlements-এ ম্যাপ করুন।
- অ্যাড-অনগুলো আলাদা আইটেম হিসেবে যোগ করুন যা entitlements গ্রান্ট বা বাড়ায়, প্ল্যান নিয়মে বেক করা নয়।
- সাধারণ পথগুলোর জন্য 5-10 টি অ্যাক্সেস টেস্ট লিখুন (মধ্য-চক্র আপগ্রেড, রিনিউয়ালে ডাউনগ্রেড, অ্যাড-অন যোগ করে পরে সরানো, ট্রায়াল থেকে পেইড, গ্রেস পিরিয়ড)।
- প্রাইসিং পরিবর্তনকে ডাটা-ওয়ান রাখুন: প্ল্যান সারি, ফিচার ম্যাপিং ও entitlement গ্রান্ট আপডেট করুন—অ্যাপ কোড নয়।
- অভ্যাস করুন: প্রতিটি নতুন প্ল্যান বা অ্যাড-অনের সাথে অন্তত একটি টেস্ট রাখা বাধ্যতামূলক করুন যা অ্যাক্সেস প্রত্যাশিতভাবে আচরণ করে কিনা প্রমাণ করে।
আপনি যদি নো-কোড ব্যাকএন্ড ব্যবহার করেন, তখনও এই প্যাটার্ন পরিষ্কারভাবে মডেল করা যাবে। AppMaster-এ Data Designer কোর টেবিলগুলো (plans, features, subscriptions, subscription items, entitlements) তৈরির জন্য ভাল। তারপর Business Process Editor-এ অ্যাক্সেস ডিসিশন ফ্লো রাখুন (active entitlements লোড করা, টাইম উইন্ডো প্রয়োগ, allow/deny রিটার্ন) যাতে এন্ডপয়েন্টে ছড়িয়ে থাকা কাস্টম কোড না লাগে।
লাভ দেখতে পাবেন যখন পরের বার প্রাইসিং বদলাবে। আপনি কোড রিরাইট না করে কেবল ডাটা এডিট করবেন: একটি ফিচার Pro থেকে অ্যাড-অনে সরানো, একটি entitlement সময়কালের পরিবর্তন, অথবা লেজেসি প্ল্যানের পুরোনো গ্রান্ট রাখা—আপনার অ্যাক্সেস লজিক স্থিতিশীল থাকবে, এবং আপগ্রেড হবে একটি নিয়ন্ত্রিত ডাটা আপডেট, কোড স্প্রিন্ট নয়।
যদি দ্রুত আপনার স্কিমা যাচাই করতে চান, একটি আপগ্রেড এবং একটি অ্যাড-অনের মডেল এক্সএন্ড-টু-এন্ড তৈরি করে দেখুন, তারপর ওই অ্যাক্সেস টেস্টগুলো চালিয়ে দেখুন সব স্মুথি কাজ করে কিনা।


