একজন রোগী “Disconnect My Data” লেখা একটি বাটনে ক্লিক করেন। ওয়েব অ্যাপটি একটি সবুজ টিক চিহ্ন এবং একটি আনন্দদায়ক নিশ্চিতকরণ দেখায়। ব্যাকগ্রাউন্ড কিউতে কোথাও, একটি ওয়ার্কার প্রসেস তার নৈশ সিঙ্কের (nightly sync) জন্য জেগে ওঠে, গতকাল তৈরি করা একটি জব টানে এবং দুই বছরের ওষুধের ইতিহাস একটি ডাউনস্ট্রিম অ্যানালিটিক্স ক্লাস্টারে স্ট্রিম করতে শুরু করে। ব্যবহারকারী ইন্টারফেসটিকে বিশ্বাস করেছিলেন। সিস্টেম সেই বিশ্বাস ভঙ্গ করেছে।
এই নির্দিষ্ট ধরণের ব্যর্থতা স্বাস্থ্য সংক্রান্ত ডেটা আর্কিটেকচারকে তাড়া করে বেড়ায় কারণ এখানে ঝুঁকি অনেক বেশি। একটি মেয়াদোত্তীর্ণ অনুমতি (stale permission) কোনো ছোটখাটো বাগ নয়; এটি একটি সক্রিয় লঙ্ঘন (breach)। এর সমাধান হলো প্রতিটি ডেটা রিকোয়েস্টকে একটি consent receipt-এর সাথে যুক্ত করা: একটি ছোট, সুসংগঠিত রেকর্ড যা ব্যবহারকারীর উদ্দেশ্যকে UI থেকে আপনার পলিসি ইঞ্জিন, ডেটাবেস ট্রানজ্যাকশন এবং প্রতিটি ব্যাকগ্রাউন্ড ওয়ার্কার পর্যন্ত বহন করে নিয়ে যায়। এটি কখনোই ক্লিনিক্যাল ভ্যালু সংরক্ষণ করে না। এটি কেবল সেগুলোতে অ্যাক্সেস করার অধিকার সংরক্ষণ করে, যা একটি ভার্সন নম্বর দিয়ে চিহ্নিত থাকে যাতে এটি পর্দার আড়ালে নিঃশব্দে পরিবর্তিত না হতে পারে।
রিসিটটি আসলে কী বহন করে
রিসিটটিকে একটি সেশন ফ্ল্যাগ হিসেবে নয়, বরং একটি স্কোপড কন্ট্রাক্ট (scoped contract) হিসেবে ভাবুন। এতে একটি গ্র্যান্ট আইডেন্টিফায়ার (grant identifier), ডেটা সাবজেক্ট, অ্যাক্সেসের সঠিক স্কোপ (ল্যাব রেজাল্ট, ভাইটালস, ওষুধের ইতিহাস), একটি নির্দিষ্ট সময়ের বৈধতা এবং একটি ভার্সন নম্বর থাকে। যখন একটি ফ্রন্টএন্ড কোনো ব্যবহারকারীর পক্ষ থেকে অ্যাক্সেসের অনুরোধ করে, তখন API এই রিসিটটি প্রদান করে। ফ্রন্টএন্ড এটি ধরে রাখে। যে কোনো ডাউনস্ট্রিম সার্ভিস স্বাস্থ্য সংক্রান্ত ডেটা পড়তে চাইলে তাকে একটি কেন্দ্রীয় পলিসি লেয়ারে এই রিসিটটি উপস্থাপন করতে হবে এবং রেকর্ডটি খোলার আগে একটি স্পষ্ট অনুমতি গ্রহণ করতে হবে।
এটি গুরুত্বপূর্ণ কারণ স্বাস্থ্য ব্যবস্থাগুলো প্রায়ই ব্যবহারকারীর অ্যাকাউন্ট টোকেনকে সম্মতি (consent) বলে ভুল করে। একটি টোকেন বলে আপনি কে। একটি রিসিট বলে আপনি এই মুহূর্তে কী করার অনুমতি পেয়েছেন। যদি এই দুটির মধ্যে অমিল দেখা দেয়, তবে রিসিটটিই সবসময় প্রাধান্য পাবে।
সবকিছু ভার্সন করুন
আপনার কনসেন্ট স্টোরটিকে একটি append-only log হিসেবে তৈরি করুন। যখন একজন ব্যবহারকারী প্রথমবার তার ইমিউনাইজেশন রেকর্ডে অ্যাক্সেস প্রদান করেন, সেটি হলো ভার্সন এক। যদি তারা পরে নির্দিষ্ট প্রোভাইডারদের বাদ দিয়ে স্কোপ কমিয়ে দেন, বা যদি তারা সম্পূর্ণভাবে এটি প্রত্যাহার করে নেন, তবে প্রথম এন্ট্রিটি ওভাররাইট করবেন না। ভার্সন দুই লিখুন। ওয়ার্কারের হাতে থাকা রিসিটটি তখনও ভার্সন এক দেখাবে, এবং পলিসি ইঞ্জিন দেখতে পাবে যে ভার্সন এক ঠিক কী কী অনুমতি দিয়েছিল এবং একটি নির্দিষ্ট টাইমস্ট্যাম্পে সেটি কেন পরিবর্তন করা হয়েছে।
এই অপরিবর্তনীয়তা (immutability) হলো আপনার অডিট ব্যাকবোন। ছয় মাস পরে, যখন একজন কমপ্লায়েন্স অফিসার জিজ্ঞাসা করবেন কেন একটি নির্দিষ্ট ETL জব বৃহস্পতিবার বিকেলে চলেছে, তখন আপনি সেই জবটি কোন গ্র্যান্ট ভার্সনটি বহন করছিল তা ট্রেস করতে পারবেন এবং প্রমাণ করতে পারবেন যে জবটি শুরু করার সময় সেটি বৈধ ছিল। আপনি যদি ব্যবহারকারীর প্রোফাইলে একটি সিঙ্গেল বুলিয়ান ফ্ল্যাগ (boolean flag) হিসেবে কনসেন্ট সংরক্ষণ করেন, তবে আপনি সেই ইতিহাস মুছে ফেলবেন। আপনি "এটি কখনোই অনুমোদিত ছিল না" এবং "জবটি শুরু করার সময় এটি অনুমোদিত ছিল কিন্তু দুই ঘণ্টা পরে ব্যবহারকারী তার সিদ্ধান্ত পরিবর্তন করেছেন"—এই দুটির মধ্যে পার্থক্য করার ক্ষমতা হারিয়ে ফেলবেন।
সততার জন্য এন্ডপয়েন্ট ডিজাইন করুন
একটি কনসেন্ট API-এর স্পষ্ট এবং সুনির্দিষ্ট রুট থাকা উচিত। নতুন পারমিশন তৈরির জন্য POST /grants ব্যবহার করুন। একটি নির্দিষ্ট রিসিটের বর্তমান অবস্থা জানতে GET /grants/{id} ব্যবহার করুন। অনুমতি প্রত্যাহার শুরু করতে POST /grants/{id}/revoke ব্যবহার করুন। এটি দাবি করবেন না যে 'revoke' করার সাথে সাথেই আপনার পাইপলাইনে থাকা স্বাস্থ্য সংক্রান্ত ডেটার প্রতিটি কপি মুছে ফেলা সম্ভব। পরিবর্তে, একটি 202 Accepted স্ট্যাটাসসহ একটি রিভোকেশন অপারেশন আইডি (revocation operation ID) প্রদান করুন। এটি ব্যবহারকারীকে জানায় যে অনুরোধটি আসল, এটি শুরু হয়েছে এবং তারা এটি ট্র্যাক করতে পারে।
ইন্টারফেস ধীরগতির মনে হওয়ায় ব্যবহারকারী যদি ডাবল-ক্লিক করেন, তখন সেই অপারেশন আইডিটি অত্যন্ত গুরুত্বপূর্ণ হয়ে ওঠে। যদি তারা দ্বিতীয়বার রিভোকেশন রিকোয়েস্ট পাঠান, তবে মূল অপারেশন আইডিটিই ফেরত দিন। এখানে আইডেমপোটেন্সি (idempotency) কেবল একটি বাড়তি সুবিধা নয়; এটি অতিরিক্ত আতঙ্ক রোধ করে এবং ব্যবহারকারীকে তাদের অনুরোধের স্ট্যাটাস সম্পর্কে একটি একক সত্যের উৎস (single source of truth) প্রদান করে।
শেষ সম্ভাব্য মুহূর্তে অনুমতি চান
একটি সাধারণ ভুল হলো API গেটওয়েতে কনসেন্ট চেক করা এবং তারপর ওয়ার্কারের ভেতরে থাকা একটি ক্যাশ করা ফ্ল্যাগকে বিশ্বাস করা। এমনটি করবেন না। ওয়ার্কারকে তার জব লাইফসাইকেল জুড়ে রিসিটটি বহন করতে হবে। হেলথ রেকর্ড স্টোরের বিরুদ্ধে কুয়েরি চালানোর ঠিক আগে, তাকে অবশ্যই পলিসি লেয়ারকে জিজ্ঞাসা করতে হবে: “এই নির্দিষ্ট গ্র্যান্টের ভার্সন তিন কি এখনও এই নির্দিষ্ট স্কোপের জন্য বৈধ?” যদি উত্তর 'না' হয়, তবে ওয়ার্কার থেমে যাবে। এটি জবটি ফেল করবে। এটি পুনরায় চেষ্টা (retry) করবে না।
এখানে রিট্রাই লজিক (retry logic) বিষের মতো। ভার্সন মিসম্যাচ কোনো নেটওয়ার্ক সমস্যা নয়। এটি একটি মানুষের সিদ্ধান্ত। ব্যবহারকারী অনুমতি প্রত্যাহার করেছেন, অথবা গ্র্যান্টের মেয়াদ শেষ হয়ে গেছে, অথবা স্কোপ কমে গেছে। আপনি যদি তিনবার রিট্রাই করেন এবং চতুর্থবার রেস কন্ডিশনের (race condition) কারণে সফল হন, তবে আপনি কেবল কনসেন্ট বা সম্মতি লঙ্ঘন করেছেন। এই মিসম্যাচটিকে একটি হার্ড ফেইলিউর (hard failure) হিসেবে গণ্য করুন, এটিকে আপনার dead-letter queue বা অপারেশনস ড্যাশবোর্ডে পাঠিয়ে দিন এবং একজন মানুষকে এটি তদন্ত করতে দিন।
জটিল পরিস্থিতিগুলো সামলান
বাস্তব সিস্টেমগুলো সুশৃঙ্খল ধাপে চলে না। ব্যবহারকারীরা পুরনো ব্রাউজার ট্যাব খোলা রেখে দেন। বাল্ক ইমপোর্ট (Bulk imports) বিশ মিনিট ধরে চলতে পারে। সিঙ্ক (sync) অর্ধেক চলা অবস্থায় স্কোপ (Scopes) পরিবর্তিত হতে পারে। আপনার কনসেন্ট API-এর জন্য এই মুহূর্তগুলোর জন্য সুনির্দিষ্ট নিয়মের প্রয়োজন।
পুরনো বা স্টেল (Stale) ব্রাউজার ট্যাব। একজন ব্যবহারকারী একটি নতুন খোলা ট্যাবে অ্যাক্সেস বাতিল (revoke) করে ফেলেন। একটি পুরনো ট্যাব, যা আগের পেজ লোড থেকে একটি গ্র্যান্ট অবজেক্ট (grant object) ধরে রেখেছে, পুনরায় কানেক্ট করার চেষ্টা করে। আপনার ব্যাকএন্ডকে অবিলম্বে সেই পুরনো রসিদ (stale receipt) প্রত্যাখ্যান করতে হবে এবং নতুন করে কনসেন্ট রিভিউ করতে বাধ্য করতে হবে। একটি বাতিল করা গ্র্যান্ট বাতিল করা পাসপোর্টের মতো আচরণ করা উচিত: এর ধারক ড্রয়ারে একটি পুরনো কপি খুঁজে পেলেই সেটি আবার কার্যকর হয়ে উঠবে না।
চলমান ইমপোর্ট (In-flight imports)। যদি একটি বাল্ক ইমপোর্ট চলতে থাকে এবং ব্যবহারকারী সেটি বাতিল করে দেন, তবে আপনার একসাথে দুটি কাজ করার প্রয়োজন। প্রথমত, ভার্সনটি প্রত্যাখ্যান করার সাথে সাথে নতুন রাইট (writes) করার অনুমতি বন্ধ করে দিন। দ্বিতীয়ত, অপারেশন আইডি (operation ID)-এর মাধ্যমে ব্যবহারকারীকে প্রকৃত ক্লিনআপ প্রগ্রেস দেখান। তাদের একটি সত্যনিষ্ঠ স্ট্যাটাস পেজ দিন: “বাতিলকরণ গৃহীত হয়েছে। আঠারোটি পেন্ডিং রাইট মুছে ফেলা হচ্ছে।” যে গ্র্যান্ট ভার্সনটি ইতিমধ্যে অবৈধ হিসেবে চিহ্নিত করা হয়েছে, সেটি ব্যবহার করে ওয়ার্কারদের ডেটা কমিট করতে দেবেন না।
স্কোপ পরিবর্তন (Scope changes)। ধরুন একজন ব্যবহারকারী প্রাথমিকভাবে পাঁচ বছরের হিস্ট্রির অ্যাক্সেস দিয়েছিলেন এবং পরে তা পরিবর্তন করে ছয় মাস করে দিলেন। মূল গ্র্যান্টটি পরিবর্তন (mutate) করবেন না। ভার্সন ওয়ান বন্ধ করুন, আরও সীমিত উইন্ডো সহ ভার্সন টু ইস্যু করুন এবং চলমান যেকোনো প্রক্রিয়াকে নতুন সীমার সাথে সামঞ্জস্য করতে বাধ্য করুন। পুরনো ভার্সনটি আপনার লগে একটি ঐতিহাসিক তথ্য হিসেবে থাকবে, কোনো সক্রিয় অনুমতি হিসেবে নয়।
কঠোর নিরাপত্তা নিয়মাবলী
রসিদগুলো নিজেই সংবেদনশীল, কিন্তু সেগুলো ক্লিনিক্যাল ডেটা নয়। আপনার আর্কিটেকচারে সেগুলোকে আলাদা রাখুন। শুধুমাত্র রোগী বা বিশেষভাবে মনোনীত কোনো ভূমিকা—যেমন আইনি অভিভাবক বা অনুমোদিত কেয়ারগিভার—রসিদ দেখতে বা বাতিল করতে সক্ষম হওয়া উচিত। এটি শুধুমাত্র UI রাউটিং টেবিলে নয়, বরং ডেটা লেয়ারে প্রয়োগ করুন।
জব ফেইল করলে আপনার এরর লগগুলো স্বাস্থ্য সংক্রান্ত ডেটা টেনে নেওয়ার চেষ্টা করবে। এই প্রবণতার বিরুদ্ধে কঠোরভাবে লড়াই করুন। যখন কোনো ওয়ার্কার একটি অবৈধ কনসেন্ট রসিদ দেখানোর কারণে কাজ বন্ধ করে দেয়, তখন গ্র্যান্ট আইডি, ভার্সন এবং এররটি লগ করুন। রোগীর আইডেন্টিফায়ার, রোগ নির্ণয়ের কোড (diagnosis code) বা ল্যাব ভ্যালু যা ওয়ার্কারটি সংগ্রহ করার চেষ্টা করছিল, তা কখনোই লগ করবেন না। লগে থাকা স্বাস্থ্য সংক্রান্ত ডেটা ছাঁচ বা মোল্ডের মতো ছড়িয়ে পড়ে: এটি ব্যাকআপ হয়, ইনডেক্স হয় এবং এমনভাবে ভুলে যাওয়া হয় যা আপনার সাধারণ অ্যাক্সেস কন্ট্রোলকে এড়িয়ে যায়।
পরিশেষে, সিস্টেম রিকভারির সময় কখনোই কোনো পুরনো সক্রিয় গ্র্যান্ট পুনরুদ্ধার করবেন না। আপনি যদি কোনো ডেটাবেস রোলব্যাক করেন বা এমন কোনো স্ন্যাপশট রিস্টোর করেন যাতে গ্র্যান্ট টেবিলের বাতিলকরণের আগের ভার্সনটি থাকে, তবে আপনার রানবুককে (runbook) সার্ভিসটি নতুন ট্রাফিক গ্রহণ করার আগেই সেই পুনরুজ্জীবিত অনুমতিগুলো স্বয়ংক্রিয়ভাবে নিষ্ক্রিয় করতে হবে। ঐতিহাসিক কনসেন্ট স্টেটগুলো অডিট লগে থাকা উচিত, সক্রিয় রুল সেটে নয়।
