Consent SaaS — মাস্টার প্ল্যান

একটি Consent Management Platform (CMP), SaaS হিসেবে। যেকোনো ওয়েবসাইট একটা <script> বসিয়ে GDPR/CCPA-অনুযায়ী কুকি সম্মতি সংগ্রহ, ট্র্যাকার ব্লকিং, কুকি স্ক্যান ও সম্মতির রেকর্ড পাবে।

সংস্করণ ১.০ ৩১ আগস্ট ২০২৬ স্ট্যাক চূড়ান্ত এটাই একমাত্র রেফারেন্স ডকুমেন্ট

১ · প্রোডাক্ট সংজ্ঞা

এক বাক্যে

ক্লায়েন্ট তার ওয়েবসাইটে আমাদের একটা ছোট <script> বসাবে। সেটা পেজে সবার আগে পৌঁছে ট্র্যাকারদের আটকে রাখবে, ভিজিটরকে সম্মতি জিজ্ঞেস করবে, সম্মতি পেলে ছেড়ে দেবে, আর প্রতিটা সম্মতি আমাদের ডাটাবেসে প্রমাণ হিসেবে রাখবে। পাশাপাশি ক্লায়েন্টের সাইট স্ক্যান করে বলে দেবে সেখানে আসলে কী কী কুকি ও ট্র্যাকার আছে।

৫টা ক্রিয়া — প্রোডাক্টের সবটুকু

১. SCAN   → সাইটে কী কী ট্র্যাকার/কুকি আছে জানো
২. BLOCK  → সম্মতির আগে ওদের ঘুম পাড়িয়ে রাখো
৩. ASK    → ভিজিটরকে ব্যানার দেখিয়ে জিজ্ঞেস করো
৪. WAKE   → যে ক্যাটাগরিতে হ্যাঁ, শুধু সেগুলো জাগাও
৫. LOG    → কে কখন কী বলল, প্রমাণ হিসেবে লিখে রাখো
স্কোপের নিয়ম

কোনো ফিচার নিয়ে সন্দেহ হলে জিজ্ঞেস করুন — এটা কি এই ৫টার কোনো একটাকে ভালো করছে? না হলে সেটা এই সংস্করণে নেই।

কী সমস্যা সমাধান করে

  • ইউরোপ/ব্রিটেন/ক্যালিফোর্নিয়ার ভিজিটর এলে আইনত সম্মতি নিতে হয় — না নিলে জরিমানা।
  • সাইট মালিক জানেই না তার সাইটে কয়টা কুকি বসে, কে বসায়।
  • ব্যানার দেখালেই হয় না — সম্মতির আগে ট্র্যাকার চললে আইন ভাঙা হয়েই যায়।
  • রেগুলেটর প্রমাণ চাইলে দেখানোর মতো রেকর্ড থাকে না।

যা আমরা দাবি করব না

“আপনি ১০০% আইনি সুরক্ষিত” — এটা বলা যাবে না। আমরা টুল দিই, আইনি পরামর্শ নয়। compliance নির্ভর করে ক্লায়েন্টের সাইট, তার ব্যবহৃত থার্ড-পার্টি টুল, অঞ্চল আর কনফিগারেশনের উপর। শর্তাবলী ও মার্কেটিং — সব জায়গায় এই ভাষা এক রাখতে হবে।

২ · ব্যবহারকারী ও ভূমিকা

কেকী করেকোন অংশ ব্যবহার করে
ভিজিটরক্লায়েন্টের সাইটে আসে, ব্যানার দেখে, Accept/Decline চাপে। আমাদের অস্তিত্বই জানে না।embed script + ব্যানার
সাইট মালিকসাইন আপ করে, স্ক্রিপ্ট বসায়, ব্যানার সাজায়, লগ দেখে, টাকা দেয়ড্যাশবোর্ড
এজেন্সিএক অ্যাকাউন্টে বহু ক্লায়েন্ট সাইট চালায়ড্যাশবোর্ড (মাল্টি-সাইট)
আমাদের সাপোর্ট টিমসমস্যা তদন্ত করে, অ্যাকাউন্ট দেখেইন্টারনাল অ্যাডমিন (§২১)
সবচেয়ে গুরুত্বপূর্ণ অনুপাত

ভিজিটরের সংখ্যা কাস্টমারের চেয়ে হাজার গুণ বেশি। ১০০ কাস্টমার = দিনে ১০ লাখ ভিজিটর হতে পারে। তাই ভিজিটর-মুখী অংশ (script + consent API) আর কাস্টমার-মুখী অংশ (ড্যাশবোর্ড) আলাদা ডিজাইন করতে হবে। একসাথে বানালে ড্যাশবোর্ডের একটা ধীর কোয়েরি পুরো সিস্টেম বসিয়ে দেবে।

৩ · শব্দকোষ

কাজ করতে করতে ভুলে গেলে এখানে ফিরে আসুন।

ওয়েবের মৌলিক

শব্দমানেউপমা
BrowserChrome/Firefox — যা ওয়েবসাইট দেখায়রেস্টুরেন্টের খদ্দের
Server২৪ ঘণ্টা চালু কম্পিউটার, ফাইল পাঠায়রান্নাঘর
HTMLপেজের কাঠামোরেসিপির কাগজ
<head>HTML-এর উপরের অদৃশ্য অংশ; স্ক্রিপ্ট এখানে বসেরান্নার প্রস্তুতি
DOMHTML থেকে ব্রাউজার যে জীবন্ত, বদলানো যায় এমন গাছ বানায়টেবিলে সাজানো আসল খাবার
MutationObserverDOM বদলালেই খবর দেওয়ার ব্রাউজার-সুবিধাদরজার CCTV + দারোয়ান
iframeএক পেজের ভেতর আরেক পেজ (YouTube, Maps)টেবিলের উপর ছোট টেবিল
Tracking pixel১×১ অদৃশ্য ছবি; লোড হলেই সার্ভারে খবর যায়প্লেটের নিচে লুকানো ঘণ্টা

আমাদের ডোমেইন

শব্দমানে
Cookieব্রাউজারে রাখা ছোট নোট: নাম + মান + মেয়াদ
First-partyযে সাইটে আছি সে নিজে বসিয়েছে (সাধারণত নিরীহ)
Third-partyবাইরের কোম্পানি বসিয়েছে (Google, Meta) — মূল সমস্যা
Trackerকুকি যে বসায় — সেই স্ক্রিপ্ট / iframe / pixel
Consentভিজিটরের দেওয়া সম্মতি
CategoryNecessary / Functional / Analytics / Marketing
CMPConsent Management Platform — আমরা যেটা বানাচ্ছি
GDPR / CCPAইউরোপ / ক্যালিফোর্নিয়ার প্রাইভেসি আইন
Google Consent Mode v2Google ট্যাগগুলোকে সম্মতির অবস্থা জানানোর মানসম্মত উপায়

SaaS ও ইনফ্রা

শব্দমানেউপমা
SaaSসফটওয়্যার ভাড়া, মাসিক ফিগাড়ি কেনার বদলে Uber
Tenantএকজন কাস্টমারএকজন ভাড়াটে
Multi-tenantএক সিস্টেম, হাজার কাস্টমার, সবার ডেটা আলাদাএক বিল্ডিং, আলাদা তালা
Embed scriptকাস্টমার যেটা কপি করে নিজের সাইটে বসায়প্লাগ
CDN / Edgeপৃথিবীজুড়ে ফাইলের কপি, কাছেরটা থেকে দেয়প্রতি জেলায় দোকান
API / Endpointপ্রোগ্রামে-প্রোগ্রামে কথা বলার নিয়ম / একটা ঠিকানামেনু কার্ড / মেনুর আইটেম
UUIDবিশ্বজুড়ে অদ্বিতীয় লম্বা আইডিNID নম্বর
Queue + Workerভারী কাজ লাইনে রেখে পরে আলাদা প্রোগ্রাম করেরান্নাঘরে টাঙানো অর্ডার স্লিপ
Headless browserপর্দা ছাড়া Chrome, সার্ভারে চলেঅদৃশ্য মানুষ
Crawlলিংক ধরে ধরে পুরো সাইট ঘোরাজাল বেয়ে হাঁটা মাকড়সা
Hashফেরত আনা যায় না এমন রূপান্তরমাংস থেকে কিমা
Indexডাটাবেসে দ্রুত খোঁজার ব্যবস্থাবইয়ের সূচিপত্র

ব্যবসা

শব্দমানে
Moatপ্রতিযোগী নকল করতে পারে না এমন সুবিধা
Freemiumবেসিক ফ্রি, ভালোটা টাকায়
White-labelআমাদের নাম মুছে কাস্টমারের নাম বসানো
Churnপ্রতি মাসে কত % কাস্টমার চলে যায় (ফুটো বালতি)
MRRমাসিক নিয়মিত আয়
Entitlementকোন প্ল্যানে কোন ফিচার/সীমা খোলা

৪ · সম্পূর্ণ ফিচার তালিকা

এটাই স্কোপের চূড়ান্ত সংজ্ঞা। এর বাইরের কিছু এই সংস্করণে নেই।

ফ্রি ফিচার

#ফিচারবিস্তারিত
Consent BannerCard ও Bar — দুই লেআউট; ৯টা পজিশন; overlay চালু/বন্ধ; border-radius; background/text/accent রং; হেডলাইন ও বর্ণনার লেখা; বাটনের লেখা — সব কোড ছাড়াই এডিটযোগ্য
তিন অ্যাকশন + PreferencesAccept All · Decline · Preferences মডাল। Decline ও Preferences বাটন আলাদা করে লুকানো-দেখানো যায়
৪ ক্যাটাগরিNecessary (locked) · Functional · Analytics · Marketing
লাইভ প্রিভিউড্যাশবোর্ডে ব্যানার সাজানোর সময় সাথে সাথে দেখা যায়
Script Blockingদুই মোড — Log Only (শুধু রেকর্ড) ও Strict (সম্মতির আগে ব্লক)। জনপ্রিয় ট্র্যাকারের প্যাটার্ন বিল্ট-ইন (Analytics, Ads, Pixel, Heatmap, Chat, CRM ইত্যাদি)
Google Consent Mode v2টগলযোগ্য; ভিজিটরের ব্রাউজারে Google ট্যাগের জন্য সম্মতির সংকেত পাঠায়
Cookie Scannerম্যানুয়ালি চালানো স্ক্যান; sitemap থাকলে সেখান থেকে, নাহলে হোম + সাম্প্রতিক পেজ থেকে — একই ডোমেইনে সর্বোচ্চ ৫০ URL
Cookie Inventoryদেখা, এডিট, ক্যাটাগরি বদল, bulk অ্যাকশন, ম্যানুয়ালি কুকি যোগ, regex প্যাটার্ন সাপোর্ট
Consent Logsconsent id, status, প্রদত্ত ক্যাটাগরি, page URL, banner version, timestamp — সার্চ ও ফিল্টারযোগ্য
১০এক্সপোর্টসম্পূর্ণ রেকর্ড CSV; একক সম্মতির receipt PDF
১১Dashboard + Compliance Score৭-পয়েন্ট চেকলিস্ট ও স্কোর; মোট consent; accept rate; active cookies (ক্যাটাগরিভিত্তিক); recent activity
১২Scan Historyআগের স্ক্যান — সময়, পেজ সংখ্যা, পাওয়া কুকির সংখ্যা, নতুন কুকি, ফলাফলের সারাংশ
১৩Settingsconsent mode · consent expiry · log retention · Google Consent Mode টগল · uncategorized কুকির আচরণ (সবসময় ব্লক / marketing ধরা) · ম্যানুয়াল ক্যাটাগরি মনে রাখা · manage pill দেখানো
১৪Manage pillভাসমান ছোট আইকন — ভিজিটর যেকোনো সময় মত বদলাতে পারে
১৫Retention cleanupনির্ধারিত মেয়াদ পেরোনো consent log স্বয়ংক্রিয়ভাবে মুছে যায়
১৬Notificationsড্যাশবোর্ডে বিজ্ঞপ্তি (স্ক্যান শেষ, নতুন ট্র্যাকার পাওয়া গেছে ইত্যাদি) + acknowledge
১৭Cookie Declarationপাবলিক কুকি তালিকা — ক্লায়েন্ট তার প্রাইভেসি পলিসি পেজে বসাতে পারে
#ফিচারবিস্তারিত
Scheduled automatic scansনির্ধারিত সময়ে (দৈনিক/সাপ্তাহিক/মাসিক) নিজে নিজে স্ক্যান
Geo targetingদেশ অনুযায়ী ব্যানার দেখানো বা লুকানো
IntegrationsGoogle Tag Manager · Meta Pixel · Adobe Experience Platform
Trust Badgeসাইটের ফুটারে “Privacy Protected” ব্যাজ
Custom CSSব্যানারে নিজের CSS দেওয়ার সুযোগ
মাল্টি-সাইটএক অ্যাকাউন্টে একাধিক সাইট
বর্ধিত সীমাবেশি স্ক্যান পেজ, দীর্ঘ log retention, বেশি এক্সপোর্ট
Priority supportসাপোর্ট নীতি — কোড নয়

৫ · সিস্টেমের ৪ স্তর

সবচেয়ে গুরুত্বপূর্ণ আর্কিটেকচার সিদ্ধান্ত। এই ৪টার চাহিদা সম্পূর্ণ ভিন্ন, তাই আলাদা রাখতে হবে।

স্তরকী করেট্রাফিকধরনব্যর্থ হলে
A · Edge / CDNembed script ও কনফিগ পরিবেশন🔴 বিশালRead-only, ক্যাশডক্লায়েন্টের সাইটে ব্যানারই আসে না
B · Consent APIভিজিটরের পছন্দ জমা নেয়🔴 বিশালWrite-heavyপ্রমাণ হারায় — আইনি ঝুঁকি
C · Admin Appড্যাশবোর্ড, সেটিংস, বিলিং🟢 কমসাধারণ CRUDকাস্টমার বিরক্ত, কিন্তু সাইট চলে
D · Scannerক্রল করে কুকি/ট্র্যাকার খোঁজা🟡 ব্যাচভারী, ধীর, CPU/RAM খায়ডেটা পুরোনো হয়, কিছু ভাঙে না
কেন আলাদা রাখতেই হবে

Scanner একটা হেডলেস Chrome চালায় — প্রতি ইনস্ট্যান্স ৩০০MB+ RAM খায়। সেটা Consent API-র সাথে একই সার্ভারে থাকলে একটা বড় স্ক্যান চললেই ভিজিটরদের সম্মতি সেভ হওয়া বন্ধ হয়ে যাবে। এক স্তরের সমস্যা যেন অন্য স্তরে না ছড়ায় — এটাই মূল নীতি।

৬ · আর্কিটেকচার

┌───────────────── ক্লায়েন্টের ওয়েবসাইট (ভিজিটরের ব্রাউজার) ──────────────────┐
│                                                                            │
│  <head>  ← আমাদের স্ক্রিপ্ট এখানে সবার আগে                                  │
│  ┌──────────────────────────────────────────────────────┐                  │
│  │  cmp.js  (< 20KB gzip)                               │                  │
│  │   1. site_id দেখে কনফিগ আনে (CDN থেকে, ক্যাশড)        │                  │
│  │   2. MutationObserver বসায়  ← 🛡️ পাহারা শুরু           │                  │
│  │   3. document.cookie setter দখল করে                   │                  │
│  │   4. আগের consent কুকি পড়ে                            │                  │
│  │   5. দরকার হলে ব্যানার আঁকে                            │                  │
│  │   6. Google Consent Mode সংকেত পাঠায়                  │                  │
│  │   7. window.CMP API খুলে দেয়                          │                  │
│  └──────────────────────────────────────────────────────┘                  │
│         │                              │                                   │
│         ▼                              ▼                                   │
│  ভিজিটরের ব্রাউজারে              পেজের অন্য স্ক্রিপ্ট                          │
│  consent কুকি                    Analytics / Pixel / iframe                │
│                                  → ব্লক অথবা জাগানো                        │
└──────────────┬─────────────────────────────────────────────────────────────┘
               │ HTTPS
   ┌───────────┼────────────────────┬─────────────────────┐
   ▼           ▼                    ▼                     ▼
┌────────────────┐  ┌────────────────┐  ┌────────────────────┐
│  A · EDGE/CDN  │  │ B · CONSENT API│  │  C · ADMIN APP     │
│                │  │                │  │                    │
│ GET cmp.js     │  │ POST /consent  │  │ Auth / ড্যাশবোর্ড    │
│ GET config     │  │ (write-heavy)  │  │ ব্যানার এডিটর       │
│ GET declaration│  │ rate-limited   │  │ ইনভেন্টরি · লগ      │
│ (ক্যাশড)       │  │ origin যাচাই   │  │ বিলিং              │
└───────┬────────┘  └───────┬────────┘  └─────────┬──────────┘
        │                   │                     │
        └───────────────────┼─────────────────────┘
                            ▼
              ┌─────────────────────────────────┐
              │        🗄️  PostgreSQL            │
              │  accounts · users · sites       │
              │  banner_configs · cookies       │
              │  scans · scan_findings          │
              │  consent_logs · consent_daily   │
              │  known_cookies · known_trackers │
              └─────────────┬───────────────────┘
                            ▲
              ┌─────────────┴───────────────────┐
              │      D · SCANNER                │
              │  BullMQ + Redis → worker        │
              │  Playwright (headless browser)  │
              │  crawl → কুকি ও ট্র্যাকার ধরা    │
              └─────────────────────────────────┘

দুইটা আলাদা যাত্রা

🔵 ভিজিটরের যাত্রা (সেকেন্ডে হাজারবার)

সাইটে ঢোকা → cmp.js লোড → কনফিগ (CDN, ক্যাশড) → ব্লকিং → ব্যানার → ক্লিক → POST /consent → জাগানো। এখানে ডাটাবেস পড়া হয় না — শুধু লেখা হয়।

🟢 কাস্টমারের যাত্রা (দিনে কয়েকবার)

লগইন → ড্যাশবোর্ড → সেটিংস বদল → সেভ → নতুন কনফিগ ভার্সন প্রকাশ → স্ক্যান চালানো → লগ দেখা ও এক্সপোর্ট।

Cache invalidation — আগেই সমাধান করা আছে

কনফিগ CDN-এ ক্যাশড থাকলে দ্রুত, কিন্তু সেটিংস বদলালে পুরোনো কনফিগ কতক্ষণ থাকবে? সমাধান: কনফিগ URL-এ version নম্বর/c/{site_id}/v7.json। সেটিংস বদলালে version বাড়ে, নতুন URL মানে নতুন ফাইল। পুরোনোটা মুছতেই হয় না, cache purge-এর ঝামেলাও নেই।

৭ · টেকনোলজি স্ট্যাক

✅ চূড়ান্ত। ভিত্তি: কোম্পানির স্ট্যান্ডার্ড স্ট্যাক + প্রয়োজনীয় সংযোজন।

স্তরকী দরকারসিদ্ধান্ত
embed script (cmp.js)খুব ছোট, নির্ভরতাহীন, সব ব্রাউজারে চলেvanilla TypeScript + Vite
CDN / edgeবিশ্বজুড়ে দ্রুত, সস্তাCloudflare
Consent APIwrite-heavy, দ্রুতNext.js Route Handler (লজিক আলাদা ফাংশনে রাখা)
Admin frontendড্যাশবোর্ড, ফর্ম, চার্টNext.js (App Router) + TanStack Query
Admin backendCRUD, auth, বিলিংNext.js Route Handlers
Databaseরিলেশনাল, বিশাল টেবিল সামলাতে পারেPostgreSQL + Drizzle ORM
Validationএক schema, দুই পাশেZodpackages/shared-এ
Queueস্ক্যান জব সারিবদ্ধ করাBullMQ + Redis
Scannerহেডলেস ব্রাউজারPlaywright (আলাদা সার্ভিস)
Authলগইন, সেশন, টিমBetter Auth
Billingসাবস্ক্রিপশন, ইনভয়েসStripe
Emailভেরিফিকেশন, রিপোর্ট, রিসেটResend
File storageCSV / PDF এক্সপোর্টCloudflare R2
Monitoringভাঙলে সাথে সাথে জানাSentry + uptime চেক
Testingব্লকিংয়ের প্রমাণVitest + Playwright
Repo৩ অ্যাপ, শেয়ার্ড প্যাকেজTurborepo মনোরেপো
৩টা নিয়ম — কখনো ভাঙা যাবে না

cmp.js কখনো React বা কোনো UI ফ্রেমওয়ার্ক ছোঁবে না। CI-তে ২০KB সাইজ বাজেট — ছাড়ালে বিল্ড ফেল। কারণ এটা ক্লায়েন্টের পেজে সবার আগে পৌঁছাতে হবে; দেরি হলে ট্র্যাকার আগেই কুকি বসিয়ে ফেলবে এবং ব্লকিং ব্যর্থ হবে।

② BullMQ worker Next.js-এর ভেতরে নয় — আলাদা long-running প্রসেস।

POST /api/consent-এ কোনো লগইন নেই — ওটা পাবলিক। সুরক্ষা = site_id + Origin যাচাই + Redis rate-limit।

কেন এই পছন্দগুলো

Drizzle vs Prisma: consent_logs-এ partition, custom index, বড় ব্যাচ insert দরকার হবে — Drizzle SQL-এর কাছাকাছি, নিয়ন্ত্রণ বেশি, রানটাইম হালকা।

TanStack Query, Redux নয়: ড্যাশবোর্ডের প্রায় সব state আসলে সার্ভারের ক্যাশ (কুকি তালিকা, লগ, স্ক্যান, কনফিগ)। Redux যোগ করলে একই ডেটা দুই জায়গায় রেখে সিঙ্ক করতে হবে — অকারণ জটিলতা। লোকাল UI state-এর জন্য useState যথেষ্ট।

৮ · রিপো কাঠামো

consent-saas/                    (Turborepo মনোরেপো)
├── apps/
│   ├── web/                     Next.js
│   │   ├── app/(dashboard)/     লগইন-পরবর্তী পেজ
│   │   ├── app/api/             Route Handlers
│   │   └── lib/consent/         ⭐ consent লেখার লজিক — ফ্রেমওয়ার্ক-মুক্ত
│   ├── embed/                   vanilla TS + Vite
│   │   ├── src/blocker.ts       MutationObserver + gate
│   │   ├── src/banner.ts        UI (কোনো ফ্রেমওয়ার্ক নেই)
│   │   ├── src/consent.ts       কুকি পড়া/লেখা + API কল
│   │   ├── src/gcm.ts           Google Consent Mode v2
│   │   └── dist/cmp.js          আউটপুট — ২০KB বাজেট
│   └── scanner/                 Node + Playwright + BullMQ worker
│       ├── src/crawler.ts       URL সংগ্রহ (sitemap / লিংক)
│       ├── src/probe.ts         পেজ খুলে কুকি ও রিকোয়েস্ট ধরা
│       └── src/classify.ts      known-list মিলিয়ে ক্যাটাগরি
└── packages/
    ├── db/                      Drizzle schema + migration
    ├── shared/                  ⭐ Zod schema — ব্রাউজার ও সার্ভারে একই
    └── known-data/              known_cookies + known_trackers (সিড ডেটা)
দুইটা নকশাগত সিদ্ধান্ত

lib/consent/ ফ্রেমওয়ার্ক-মুক্ত: consent লেখার কোড Next.js-এর সাথে জড়াবে না। ট্রাফিক বাড়লে ওটাকে edge-এ সরানো তখন কয়েক দিনের কাজ, কয়েক মাসের না।

packages/shared: consent-এর আকৃতি একবার লিখব — embed পাঠানোর আগে যাচাই করবে, web নেওয়ার সময় যাচাই করবে। এক সত্য, দুই জায়গায়।

৯ · ইঞ্জিন ১ — Blocking

এটাই প্রোডাক্টের হৃদয়। এটা না পারলে বাকিটা শুধু একটা সুন্দর পপ-আপ।

মূল অন্তর্দৃষ্টি

আমরা কুকি ব্লক করি না — কুকি যে বানায়, সেই HTML এলিমেন্টকে চলতে দিই না। কুকি বসে যাওয়ার পর আটকানোর কিছু থাকে না; তার আগেই থামাতে হয়।

যা যা ব্লক করতে হবে

#লক্ষ্যকৌশল
<script src>typetext/plain, srcdata-src
ইনলাইন <script>typetext/plain
<iframe>srcdata-src + প্লেসহোল্ডার দেখানো
<img> (tracking pixel)srcdata-src
document.cookiesetter দখল করে unapproved হলে চুপচাপ ফেলে দেওয়া
<link rel=preconnect/prefetch>সরিয়ে দেওয়া

লজিক

cmp.js লোড হলো (সবার আগে)
   │
   ├─ কনফিগ + block-list মেমোরিতে নাও
   ├─ document.cookie-এর setter দখল করো
   ├─ Google Consent Mode ডিফল্ট সংকেত পাঠাও (denied)
   └─ MutationObserver চালু করো  ────┐
                                     │
   পেজে নতুন এলিমেন্ট ঢুকতে চাইলে ◄───┘
                │
        এর URL/domain block-list-এ আছে?
                │
        ┌───────┴────────┐
       না               হ্যাঁ
        │                │
     ছেড়ে দাও    এই ক্যাটাগরিতে সম্মতি আছে?
                         │
                 ┌───────┴────────┐
                হ্যাঁ            না
                 │                │
             ছেড়ে দাও      🔒 পঙ্গু করো
                             (মুছবে না — জমা রাখো)
                                  │
                       ভিজিটর পরে Accept চাপলে
                                  ▼
                          জমানো এলিমেন্ট আসল রূপে
                          + GCM সংকেত আপডেট (granted)

দুই মোড

Log Only (ডিফল্ট)

কিছুই ব্লক করে না, শুধু সম্মতি রেকর্ড করে। নতুন কাস্টমার প্রথমে এটা দিয়ে দেখে নেয় কী ধরা পড়ছে, সাইট ভাঙবে কিনা।

Strict (Block Until Consent)

আসল compliance। সম্মতি ছাড়া কিছু চলে না। কাস্টমার নিজে হাতে চালু করবে — আমরা জোর করব না।

Uncategorized কুকির আচরণ

স্ক্যানে এমন কুকি পাওয়া যেতে পারে যা চেনা তালিকায় নেই। কাস্টমার সেটিংসে ঠিক করবে —

  • Block always (ডিফল্ট, নিরাপদ) — অজানা মানেই ব্লক
  • Marketing হিসেবে ধরো — কম কড়া, কম সাইট ভাঙে
Escape hatch — শুরু থেকেই থাকতে হবে

কোনো স্ক্রিপ্ট ব্লক না করার উপায় বাধ্যতামূলক: <script data-cmp="ignore">। না দিলে কাস্টমারের পেমেন্ট গেটওয়ে বা চ্যাট উইজেট ভেঙে যাবে আর দোষ আমাদের ঘাড়ে পড়বে।

iframe প্লেসহোল্ডার

ভিডিও ব্লক করলে সাদা ফাঁকা জায়গা থাকবে — ভিজিটর ভাববে সাইট ভাঙা। ওখানে একটা বাক্স দেখান: “এই কনটেন্ট দেখতে marketing কুকিতে সম্মতি দিন [Accept]”। ছোট ফিচার, কিন্তু কাস্টমাররা এটা খুব পছন্দ করে।

JavaScript API (ক্লায়েন্টের ডেভেলপারদের জন্য)

window.CMP.consent            // {necessary, functional, analytics, marketing}
window.CMP.show()             // ব্যানার আবার দেখাও
window.CMP.withdraw()         // সম্মতি প্রত্যাহার

// ইভেন্ট — দুটো আলাদা, ইচ্ছাকৃতভাবে
'cmp:consent-changed'   // ভিজিটর এইমাত্র ক্লিক করল
'cmp:consent-restored'  // আগের সম্মতি মেমোরি থেকে ফিরল

বাজারে প্রচলিত CMP-গুলোতে এই দুইটা একই ইভেন্ট — ফলে ক্লায়েন্টের analytics ডাবল-কাউন্ট হয়। আলাদা রাখলে ডেভেলপারদের কাছে এটা ছোট কিন্তু স্পষ্ট সুবিধা।

১০ · ইঞ্জিন ২ — Banner ও Consent

ভিজিটরের ফ্লো

ভিজিটর সাইটে ঢুকল
   │
   ব্রাউজারে আগের consent কুকি আছে?
   │
   ├─ হ্যাঁ, মেয়াদ আছে, কনফিগ version মেলে
   │     → ব্যানার দেখিও না
   │     → আগের পছন্দ অনুযায়ী স্ক্রিপ্ট জাগাও
   │     → 'cmp:consent-restored' ইভেন্ট
   │
   └─ না / মেয়াদ শেষ / কনফিগ version বদলেছে
         → ব্যানার দেখাও
         │
         ├─ [Accept All]      → সব ক্যাটাগরি true
         ├─ [Decline]         → শুধু necessary true
         └─ [Preferences ⚙]   → ক্যাটাগরিভিত্তিক টগল
         │                       Necessary  ✅ locked
         │                       Functional ⬜
         │                       Analytics  ⬜
         │                       Marketing  ⬜
         │
         পছন্দ সেভ হয় দুই জায়গায়:
           ১. ভিজিটরের ব্রাউজারে কুকি — পরেরবার মনে রাখতে
           ২. আমাদের DB-তে log — আইনি প্রমাণ
         │
         → অনুমোদিত স্ক্রিপ্ট জেগে ওঠে
         → GCM সংকেত আপডেট
         → 'cmp:consent-changed' ইভেন্ট

আইনি নিয়ম — ভাঙলে প্রোডাক্ট অকেজো

নিয়মকেন
Decline বাটন Accept-এর সমান সহজলুকানো বা ধূসর Decline = আইন ভাঙা
ডিফল্টে সব টগল বন্ধআগে থেকে টিক দেওয়া = সম্মতি নয়
Necessary লকড কিন্তু দৃশ্যমানবন্ধ করা যাবে না, তবে লুকানোও যাবে না
Privacy Policy লিংকবাধ্যতামূলক
মত বদলানোর স্থায়ী উপায়manage pill বা ফুটার লিংক
সম্মতির মেয়াদ ≤ ১৩ মাসশিল্পমান (CNIL নির্দেশনা)
ব্যানার বন্ধ করা = DeclineX চাপা মানে “হ্যাঁ” নয়
প্রত্যাহার যত সহজ, দেওয়াও তত সহজGDPR-এর শর্ত

ব্যানার কনফিগ (এক JSON — এটাই CDN থেকে যায়)

{
  "version": 7,
  "enabled": true,
  "layout": "card | bar",
  "position": "bottom-left | bottom-right | bottom-center |
               top-left | top-right | top-center |
               center | left | right",
  "overlay": false,
  "borderRadius": 12,
  "colors": { "bg", "text", "accent" },
  "text": {
    "headline", "description",
    "acceptText", "declineText", "settingsText"
  },
  "showDecline": true,
  "showSettings": true,
  "showManagePill": true,
  "links": { "privacyPolicy", "cookiePolicy" },
  "categories": ["necessary","functional","analytics","marketing"],
  "consentExpiryDays": 180,
  "mode": "log_only | strict",
  "googleConsentMode": true,
  "uncategorized": "block_always | marketing",
  "blockList": [ ... ],
  "geo": { "enabled": false, "countries": [] },   // paid
  "customCss": "",                                 // paid
  "trustBadge": false,                             // paid
  "branding": true                                 // paid হলে false
}
কেন একটাই JSON

cmp.js শুধু একটা জিনিস আনবে — এক রিকোয়েস্ট, ক্যাশড, দ্রুত। একাধিক API কল মানে ধীর, আর ধীর মানে ট্র্যাকার জিতে যায়।

১১ · ইঞ্জিন ৩ — Consent Log

এটাই প্রোডাক্টের আইনি মূল্য। রেগুলেটর এলে এটাই দেখানোর জিনিস।

ফিল্ডউদাহরণকেন লাগে
consent_idUUIDভিজিটরকে চেনা, নাম না জেনেই
site_idUUID🔴 multi-tenant — কখনো বাদ দেওয়া যাবে না
visitor_hashsha256একই ভিজিটরের বারবার সম্মতি আলাদা করা
created_attimestamp (UTC)কখন
statusaccepted_all / declined / custom / withdrawnকীভাবে দিল
categories{analytics:true, marketing:false}কী অনুমতি
config_version7⭐ কোন লেখা দেখে রাজি হয়েছিল — প্রমাণের প্রাণ
page_url/pricingপ্রেক্ষাপট
countryDEকোন আইন প্রযোজ্য
ua_hashsha256একই ডিভাইস কিনা
প্যারাডক্স এড়ান

প্রাইভেসি টুল বানাতে গিয়ে নিজেরাই যেন প্রাইভেসি না ভাঙি। কাঁচা IP, ইমেইল, নাম — কিছুই সেভ হবে না। শুধু hash, আলাদা গোপন salt দিয়ে।

স্কেলের বাস্তবতা — শুরু থেকেই ভাবা

১০০০ সাইট × দিনে ১০০০ ভিজিটর = দিনে ১০ লাখ রো। পরিকল্পনা:

  • মাস অনুযায়ী partition
  • প্ল্যান অনুযায়ী retention — মেয়াদ শেষে স্বয়ংক্রিয় মুছে ফেলা
  • ড্যাশবোর্ডের গ্রাফ consent_daily সারাংশ টেবিল থেকে — কাঁচা লগে COUNT করা হবে না
  • পুরোনো লগ ঠান্ডা স্টোরেজে সরানোর পথ খোলা রাখা

এক্সপোর্ট

  • CSV — পুরো তালিকা, ফিল্টার প্রযোজ্য
  • PDF receipt — একক সম্মতির আইনি ডকুমেন্ট: সাইট, সময়, consent id, ক্যাটাগরি, banner version ও সেই সময়ের ব্যানারের লেখা

বড় এক্সপোর্ট queue-তে যাবে, তৈরি হলে R2-তে রেখে ডাউনলোড লিংক দেওয়া হবে (সীমিত মেয়াদের)।

১২ · ইঞ্জিন ৪ — Scanner

লজিক

স্ক্যান শুরু (ম্যানুয়াল, অথবা paid হলে সময়মতো)
   │
   job → BullMQ queue      ← ইউজারকে সাথে সাথে “শুরু হয়েছে” বলা হলো
   │
   worker job তুলল
   │
   ├─ sitemap.xml আছে? → পেজের তালিকা নাও
   ├─ না থাকলে → হোম + সাম্প্রতিক পেজ থেকে লিংক ধরে crawl
   ├─ সীমা প্রয়োগ: একই ডোমেইন, সর্বোচ্চ N URL (প্ল্যান অনুযায়ী)
   │
   প্রতিটা পেজে (Playwright):
   │   ├─ পেজ খোলো, network idle পর্যন্ত অপেক্ষা
   │   ├─ নিচ পর্যন্ত স্ক্রল করো  ← lazy-load ট্রিগার
   │   ├─ সব নেটওয়ার্ক রিকোয়েস্টের domain রেকর্ড করো
   │   ├─ সব কুকি রেকর্ড করো (নাম, ডোমেইন, path, মেয়াদ)
   │   └─ কোন পেজে প্রথম পাওয়া গেল লিখে রাখো
   │
   known_cookies / known_trackers-এর সাথে মেলাও
   │   ├─ মিলল  → ক্যাটাগরি স্বয়ংক্রিয়ভাবে বসাও
   │   └─ মিলল না → uncategorized — কাস্টমারকে জিজ্ঞেস করো
   │
   ⭐ ম্যানুয়াল ক্যাটাগরি সংরক্ষণ
   │   কাস্টমার আগে হাতে যে ক্যাটাগরি দিয়েছিল, স্ক্যান সেটা মুছবে না
   │
   আগের স্ক্যানের সাথে তুলনা → নতুন কী এলো, কী গেল
   │
   রিপোর্ট সেভ + নোটিফিকেশন (+ paid হলে ইমেইল)
“গত স্ক্যান থেকে কী বদলেছে” — কেন এটা গুরুত্বপূর্ণ

স্ক্যান একবারের কাজ হলে কাস্টমার একবার ব্যবহার করে ভুলে যেত। “আপনার সাইট বদলায়, নতুন ট্র্যাকার ঢোকে, আমরা পাহারা দিই” — এই diff-টাই সাবস্ক্রিপশন টিকিয়ে রাখে। তাই এটা কসমেটিক নয়, ব্যবসায়িক।

খরচ ও নিরাপত্তা নিয়ন্ত্রণ

  • প্ল্যান অনুযায়ী পেজ সীমা
  • একই ডোমেইনের বাইরে যাবে না
  • একই টেমপ্লেটের বহু পেজ থেকে নমুনা নেওয়া
  • worker কনকারেন্সি সীমা, per-page টাইমআউট, রিট্রাই সীমা
  • ব্যর্থ হলে error_log-এ কারণ — কাস্টমার যেন কারণ দেখতে পায়
  • শুধু ভেরিফাইড ডোমেইন স্ক্যান করা যাবে (§১৬) — নাহলে আমাদের স্ক্যানার অন্যের সাইটে আক্রমণের হাতিয়ার হয়ে যেতে পারে
known_cookies — আমাদের moat

কোড নকল করা সহজ, কিন্তু যাচাই করা কুকি-তালিকা বানাতে মাসের পর মাস লাগে। কলাম: name_pattern (regex সহ), vendor, category, expiry, purpose, source। প্রতিটা স্ক্যানে যা uncategorized আসে সেটাই পরের এন্ট্রির উৎস — প্রোডাক্ট নিজেই নিজের তালিকা বড় করবে। এই লুপটা ইন্টারনাল টুল হিসেবে দিন ১ থেকে রাখা উচিত।

১৩ · ডাটাবেস

accounts          এক কাস্টমার/কোম্পানি
  id, name, plan, status, stripe_customer_id, created_at

users             অ্যাকাউন্টের ভেতরের মানুষ (Better Auth)
  id, account_id, email, role, ...

sites             ⭐ multi-tenant-এর কেন্দ্র
  id (UUID = embed script-এর site_id), account_id, domain,
  verified_at, config_version, created_at

banner_configs    ভার্সনসহ — পুরোনো ভার্সন কখনো মোছা হবে না
  id, site_id, version, json, published_at

cookies           প্রতি সাইটে পাওয়া/যোগ করা কুকি
  id, site_id, name, domain, path, provider,
  detected_category, manual_category, category,
  duration, duration_seconds, description,
  is_regex, is_third_party, auto_detected,
  source_type, last_detected_at, created_at, updated_at
  UNIQUE (site_id, name, domain, path)

scans
  id, site_id, status, trigger (manual|scheduled),
  pages_scanned, cookies_found, cookies_new,
  started_at, completed_at, error_log, notes

scan_findings     কাঁচা ফলাফল — diff-এর জন্য
  id, scan_id, type (cookie|request), value,
  provider, category, page_url, detected_at

consent_logs      🔥 সবচেয়ে বড় টেবিল (মাস অনুযায়ী partition)
  id, site_id, consent_id, visitor_hash, status,
  categories, config_version, page_url, country,
  ua_hash, created_at

consent_daily     ⭐ ড্যাশবোর্ডের গ্রাফের সারাংশ
  site_id, date, total, accepted_all, declined, custom

notifications
  id, site_id, type, title, body, read_at, created_at

known_cookies     গ্লোবাল — সব সাইটের জন্য এক
  id, name_pattern, is_regex, vendor, category,
  expiry, purpose, source

known_trackers    গ্লোবাল block-list
  id, domain_pattern, vendor, category, type, risk_level

শুরু থেকেই যে ইনডেক্সগুলো লাগবে

  • consent_logs (site_id, created_at) — সব ড্যাশবোর্ড কোয়েরির ভিত্তি
  • consent_logs (consent_id) — receipt বের করা ও মোছার অনুরোধ
  • cookies (site_id, category)
  • sites (id) — embed script-এর প্রবেশদ্বার, সবচেয়ে বেশি পড়া হবে
  • scans (site_id, started_at)
Multi-tenant-এর ১ নম্বর নিয়ম

site-নির্ভর প্রতিটা কোয়েরিতে site_id থাকতেই হবে, এবং সেই site লগইন করা ইউজারের অ্যাকাউন্টের কিনা যাচাই করতে হবে। একবার ভুললে এক কাস্টমার অন্যের ডেটা দেখে ফেলবে।

সুরক্ষা দুই স্তরে: ① কোডে একটাই tenant-aware ডেটা লেয়ার — কেউ সরাসরি কাঁচা কোয়েরি লিখবে না ② PostgreSQL Row Level Security।

১৪ · API

পাবলিক (ভিজিটরের ব্রাউজার — কোনো লগইন নেই)

Endpointকাজনোট
GET /cmp.jsমূল স্ক্রিপ্টCDN, দীর্ঘ ক্যাশ, সবার জন্য এক ফাইল
GET /c/{site_id}/v{n}.jsonব্যানার কনফিগCDN, immutable
POST /api/consentসম্মতি জমাrate-limit, Origin যাচাই, দ্রুত ২০০
GET /d/{site_id}.jsCookie Declaration উইজেটপ্রাইভেসি পেজে বসে, ক্যাশড

প্রাইভেট (ড্যাশবোর্ড — Better Auth)

— Auth (Better Auth) —
POST   /api/auth/*                সাইন আপ / লগইন / রিসেট

— Sites —
GET    /api/sites                 আমার সাইটগুলো
POST   /api/sites                 নতুন সাইট (site_id তৈরি)
POST   /api/sites/:id/verify      ইনস্টলেশন যাচাই
DELETE /api/sites/:id

— Banner —
GET    /api/sites/:id/banner      কনফিগ পড়া
PUT    /api/sites/:id/banner      সেভ → version++ → প্রকাশ

— Settings —
GET    /api/sites/:id/settings
PUT    /api/sites/:id/settings

— Cookies —
GET    /api/sites/:id/cookies     তালিকা (ফিল্টার, পেজিনেশন)
POST   /api/sites/:id/cookies     ম্যানুয়াল যোগ
PUT    /api/cookies/:id           এডিট / ক্যাটাগরি বদল
POST   /api/sites/:id/cookies/bulk  bulk ক্যাটাগরি / ডিলিট
DELETE /api/cookies/:id

— Scanner —
POST   /api/sites/:id/scans       স্ক্যান শুরু (queue-তে যায়)
GET    /api/sites/:id/scans       স্ক্যান হিস্ট্রি
GET    /api/scans/:id             অবস্থা ও ফলাফল

— Consent —
GET    /api/sites/:id/consents    লগ (সার্চ, ফিল্টার, পেজিনেশন)
GET    /api/consents/:id/receipt  একক PDF
POST   /api/sites/:id/exports     CSV/PDF তৈরি (queue)
DELETE /api/consents/:consentId   ভিজিটরের মোছার অনুরোধ

— Dashboard —
GET    /api/sites/:id/overview    স্কোর, সারাংশ, চেকলিস্ট
GET    /api/notifications
POST   /api/notifications/ack

— Billing —
GET    /api/billing               প্ল্যান, ইনভয়েস
POST   /api/billing/checkout      Stripe checkout
POST   /api/webhooks/stripe       Stripe → আমাদের
POST /api/consent — সবচেয়ে বেশি চাপ এখানে

নিয়ম: কোনো ভারী কাজ নয়। Zod যাচাই → লেখা → সাথে সাথে ২০০। ইমেইল, স্কোর হিসাব, summary আপডেট — সব পরে, আলাদা প্রক্রিয়ায়। এখানে ১০০ms-এর বেশি লাগলে ক্লায়েন্টের সাইট ধীর মনে হবে।

১৫ · ড্যাশবোর্ড

পেজকী থাকবে
DashboardCompliance score (৭ চেক), মোট consent, accept rate, active cookies ক্যাটাগরিভিত্তিক, recent activity, স্ক্যান শুরু করার কার্ড, Compliance Checklist
Cookie Inventoryতালিকা, ক্যাটাগরি ফিল্টার, সার্চ, ইনলাইন ক্যাটাগরি বদল, bulk অ্যাকশন, ম্যানুয়াল যোগ (regex সহ), ডিলিট
Banner Designলেআউট, পজিশন, রং, লেখা, বাটন, radius, overlay — সব লাইভ প্রিভিউ সহ; paid হলে Custom CSS
Consent Logsতালিকা, সার্চ, তারিখ/স্ট্যাটাস ফিল্টার, একক receipt PDF, CSV এক্সপোর্ট
Scan Historyস্ক্যান তালিকা, অবস্থা, পেজ ও কুকি সংখ্যা, diff রিপোর্ট, ব্যর্থতার কারণ
Settingsconsent mode, expiry, retention, GCM v2, uncategorized আচরণ, manual category মনে রাখা, manage pill, প্রাইভেসি লিংক; paid হলে geo, trust badge, scheduled scan
Installকপি করার স্ক্রিপ্ট, বসানোর নির্দেশনা, Verify installation বাটন
Billingপ্ল্যান, ব্যবহারের পরিমাণ, ইনভয়েস, আপগ্রেড

Compliance Checklist — ৭টা চেক

  1. Consent banner চালু আছে
  2. Consent mode = Strict (Log Only হলে ব্যর্থ)
  3. সব কুকি ক্যাটাগরাইজ করা
  4. Privacy policy লিংক দেওয়া
  5. গত ৩০ দিনে স্ক্যান হয়েছে
  6. Consent expiry ≤ ১৩ মাস
  7. Google Consent Mode v2 চালু
প্রতিটা চেকের পাশে “Fix it” বাটন — বাধ্যতামূলক

ক্লিক করলে ওখানেই ছোট মডাল খুলে সেটিংসটা বদলে দেবে। ইউজারকে পেজ খুঁজতে পাঠানো যাবে না।

কারণ: compliance score-এর উদ্দেশ্য নম্বর দেখানো নয় — ইউজারকে হাত ধরে ১০০%-এ নিয়ে যাওয়া। সমস্যা দেখিয়ে সমাধানের রাস্তা লুকিয়ে রাখলে ইউজার হাল ছেড়ে দেয়।

১৬ · Onboarding

SaaS-এ সবচেয়ে বেশি ইউজার এখানেই হারায়। লক্ষ্য: সাইন-আপ থেকে কাজ করা ব্যানার — ৫ মিনিট।

সাইন আপ (ইমেইল ভেরিফাই)
   ↓
ডোমেইন লিখুন  →  site_id (UUID) তৈরি
   ↓
স্ক্রিপ্ট দেখানো + কপি বাটন
   <script src="https://cdn.../cmp.js"
           data-site="xxxx-xxxx" async=false></script>
   ↓
[ Verify installation ]  ← আমরা তার ডোমেইন খুলে দেখি
   ├─ স্ক্রিপ্ট পাওয়া গেছে?
   ├─ <head>-এর যথেষ্ট উপরে আছে?
   └─ site_id মিলছে?
   ↓  ✅ সবুজ টিক — এখানেই বেশিরভাগ কাস্টমার নিশ্চিন্ত হয়
   ↓
ব্যানার সাজানো (লাইভ প্রিভিউ)  →  Enable
   ↓
প্রথম স্ক্যান চালানো  →  কুকি ক্যাটাগরাইজ করা
   ↓
প্রস্তুত হলে Strict মোডে যাওয়া

ডোমেইন ভেরিফিকেশন — কেন দরকার

যে কেউ অন্যের ডোমেইন লিখে দিতে পারবে না। ভেরিফিকেশনের কারণ দুইটা — ① আমাদের স্ক্যানার যেন অন্যের সাইটে অনাহূত ট্রাফিক না পাঠায় ② Origin যাচাই বিশ্বাসযোগ্য হয়। পদ্ধতি: স্ক্রিপ্ট পাওয়া গেলেই ভেরিফাইড ধরা যায় (স্ক্রিপ্ট বসাতে সাইটে অ্যাক্সেস লাগে), অথবা DNS TXT রেকর্ড।

ডিফল্ট নিরাপদ রাখা

নতুন সাইটে ব্যানার বন্ধ থাকবে, মোড Log Only থাকবে। কাস্টমার নিজে হাতে চালু করবে। অ্যাকাউন্ট খোলার সাথে সাথে তার লাইভ সাইটে হঠাৎ পপ-আপ এসে যাওয়া সবচেয়ে খারাপ প্রথম অভিজ্ঞতা।

১৭ · প্ল্যান ও সীমা

সীমা কোডে ছড়িয়ে রাখা যাবে না — একটাই entitlement টেবিল, একটাই চেক ফাংশন।

সীমাFreePaid
সাইট সংখ্যাপ্ল্যান অনুযায়ী
স্ক্যানে সর্বোচ্চ URL৫০বেশি
স্ক্যান ফ্রিকোয়েন্সিম্যানুয়াল+ scheduled
Consent log retentionসীমিতদীর্ঘ
এক্সপোর্টসীমিতপূর্ণ
Branding (“Powered by”)থাকেসরানো যায়
Geo · Trust badge · Custom CSS · Integrations
টিম মেম্বারএকাধিক
সীমা প্রয়োগের নিয়ম

① সীমা সার্ভারে প্রয়োগ হবে, শুধু UI-তে বাটন লুকিয়ে নয়।
② প্ল্যান ডাউনগ্রেড হলে ডেটা মোছা হবে না — শুধু অ্যাক্সেস সীমিত হবে, যেন আপগ্রেড করলেই ফিরে পায়।
③ সীমা ছাড়ালে চুপচাপ বিল বাড়ানো হবে না — কাস্টমারকে জানানো হবে, সিদ্ধান্ত তার।

১৮ · বিলিং

  • Stripe Checkout দিয়ে সাবস্ক্রিপশন; Customer Portal দিয়ে কার্ড/প্ল্যান বদল ও ইনভয়েস
  • Stripe webhook → accounts.planstatus আপডেট (এটাই সত্যের উৎস)
  • webhook idempotent হতে হবে — একই ইভেন্ট দুইবার এলে দুইবার প্রয়োগ হবে না
  • পেমেন্ট ব্যর্থ হলে grace period — ব্যানার হঠাৎ বন্ধ হয়ে ক্লায়েন্টের সাইট আইনি ঝুঁকিতে ফেলা যাবে না
  • অ্যাকাউন্ট বন্ধ হলেও ব্যানার চলতে থাকবে, শুধু ড্যাশবোর্ড সীমিত হবে
নীতিগত সিদ্ধান্ত

বিল না দিলে আমরা ভিজিটর-মুখী সেবা বন্ধ করব না। কারণ আমাদের স্ক্রিপ্ট বন্ধ হলে ক্লায়েন্টের ট্র্যাকারগুলো সম্মতি ছাড়াই চলতে শুরু করবে — সেটা তাকে আইনি বিপদে ফেলবে এবং আমাদের সুনামও নষ্ট করবে। চাপ প্রয়োগের জায়গা ড্যাশবোর্ড, ব্যানার নয়।

১৯ · নিরাপত্তা ও আইন

  • Tenant isolation — সব কোয়েরিতে site_id + মালিকানা যাচাই; Postgres RLS
  • site_id UUID — ক্রমিক নম্বর নয়
  • Origin যাচাই — সম্মতি যে ডোমেইন থেকে এলো সেটা ওই site-এর নিবন্ধিত ডোমেইন কিনা
  • Rate limiting (Redis) — ভুয়া সম্মতি দিয়ে DB ভরানো ঠেকাতে
  • শুধু hash — কাঁচা IP/ইমেইল/নাম কখনো নয়; salt আলাদা গোপন
  • CORS — পাবলিক endpoint-এ সঠিক হেডার
  • Subresource-এর নিরাপত্তা — cmp.js immutable ভার্সনড URL থেকে
  • নিজেদের প্রাইভেসি পলিসি + DPA — আমরা processor, কাস্টমার controller; সাব-প্রসেসরের তালিকা প্রকাশ
  • ডেটার অবস্থান — ইউরোপীয় কাস্টমাররা EU রিজিয়ন চাইতে পারে; আর্কিটেকচারে সেই সম্ভাবনা খোলা রাখা
  • মোছার অনুরোধ — consent_id দিয়ে ভিজিটরের রেকর্ড মোছার পথ
  • Secret ব্যবস্থাপনা — env-এ, রিপোতে নয়; ঘোরানোর পরিকল্পনা
  • অডিট ট্রেইল — কে কখন সেটিংস বদলাল (banner_configs-এর version এটার অংশ)

২০ · রিলিজ ও রোলআউট নিরাপত্তা

আমাদের স্ক্রিপ্ট হাজার হাজার লাইভ সাইটে চলে। একটা খারাপ রিলিজ = হাজারটা সাইট একসাথে ভাঙা।

cmp.js-এর ভার্সন কৌশল

https://cdn.../v1/cmp.js      ← কাস্টমার এই URL বসায় (স্থায়ী)
https://cdn.../v1.4.2/cmp.js  ← আসল immutable ফাইল

v1/cmp.js → বর্তমান স্থিতিশীল বিল্ডে পয়েন্ট করে
সমস্যা হলে এক সেকেন্ডে আগের বিল্ডে ফেরানো যায়

নিয়ম

  • ক্যানারি রোলআউট — নতুন বিল্ড প্রথমে অল্প শতাংশ সাইটে, তারপর ধাপে ধাপে
  • তাৎক্ষণিক রোলব্যাক — এক পয়েন্টার বদল, ডিপ্লয় নয়
  • ব্রেকিং চেঞ্জ = নতুন মেজর URL (/v2/cmp.js), পুরোনোটা চলতে থাকবে
  • সাইজ বাজেট CI-তে — ২০KB ছাড়ালে বিল্ড ফেল
  • ব্রাউজার ম্যাট্রিক্স — পুরোনো ব্রাউজারেও অন্তত ব্যানার দেখাবে; স্ক্রিপ্ট ক্র্যাশ করলে কখনো ক্লায়েন্টের পেজ ভাঙবে না (সব কিছু try/catch-এ মোড়ানো, ব্যর্থ হলে চুপচাপ সরে যাবে)
  • ডাটাবেস মাইগ্রেশন — সবসময় backward-compatible দুই ধাপে (আগে কলাম যোগ, পরে পুরোনো বাদ)
“Fail open” নীতি

আমাদের স্ক্রিপ্টে অপ্রত্যাশিত ত্রুটি হলে সে নিজেকে গুটিয়ে নেবে — ক্লায়েন্টের পেজ যেন স্বাভাবিক চলে। ব্যানার না আসা খারাপ, কিন্তু ক্লায়েন্টের পুরো সাইট সাদা হয়ে যাওয়া অনেক বেশি খারাপ।

২১ · অপারেশন ও সাপোর্ট

মনিটরিং — যা দেখতেই হবে

মেট্রিককেন
cmp.js লোড সময় ও ব্যর্থতার হারএটাই প্রোডাক্টের প্রাণ
POST /consent latency ও error rateপ্রমাণ হারানো = আইনি ঝুঁকি
CDN cache hit rateখরচ ও গতি
Queue depth ও worker ব্যর্থতাস্ক্যান আটকে আছে কিনা
consent_logs বৃদ্ধির হারখরচ পূর্বাভাস
Sentry — ব্রাউজার ত্রুটিক্লায়েন্টের সাইটে আমাদের স্ক্রিপ্ট ভাঙছে কিনা

ইন্টারনাল অ্যাডমিন (আমাদের নিজেদের জন্য)

  • অ্যাকাউন্ট খোঁজা, প্ল্যান দেখা, ব্যবহারের পরিমাণ
  • একটা সাইটের কনফিগ ও শেষ স্ক্যান দেখা (ডেটা না বদলে)
  • uncategorized কুকির গ্লোবাল তালিকা → known_cookies-এ যোগ করার টুল (moat বাড়ানোর লুপ)
  • একটা স্ক্যান হাতে চালানো / বাতিল করা
  • সাপোর্টের জন্য সীমিত ইমপারসোনেশন — প্রতিটা ব্যবহার লগ হবে

ব্যাকআপ ও পুনরুদ্ধার

  • নিয়মিত Postgres ব্যাকআপ + point-in-time recovery
  • পুনরুদ্ধার সত্যিই পরীক্ষা করা — যে ব্যাকআপ কখনো ফেরানো হয়নি, সেটা ব্যাকআপ নয়
  • known_cookies / known_trackers আলাদা করে রাখা — এটা আমাদের সবচেয়ে দামি ডেটা

কাস্টমার সাপোর্টের জন্য

  • ডকুমেন্টেশন: ইনস্টল, Strict মোডে যাওয়ার নির্দেশিকা, JS API, সাধারণ সমস্যা
  • “আমার সাইট ভেঙে গেছে” — প্রথম উত্তর সবসময়: Log Only-তে ফিরুন, তারপর data-cmp="ignore" দিয়ে দোষী স্ক্রিপ্ট বাদ দিন

২২ · টেস্টিং

স্তরকী পরীক্ষাটুল
ইউনিটক্যাটাগরি মিলানো, regex, কনফিগ যাচাই (Zod), entitlement চেকVitest
ইন্টিগ্রেশনAPI endpoint, tenant isolation (একজনের টোকেনে অন্যের ডেটা চাওয়া → ৪০৩)Vitest
🔥 ব্লকিংটেস্ট পেজে নকল ট্র্যাকার বসিয়ে: Accept-এর আগে ০ কুকি, পরে প্রত্যাশিত কুকিPlaywright
ব্যানার৯ পজিশন × ২ লেআউট রেন্ডার, কীবোর্ড নেভিগেশন, স্ক্রিন রিডারPlaywright
স্ক্যানারজানা কুকিওয়ালা ফিক্সচার সাইট → প্রত্যাশিত ফলাফলPlaywright
সাইজcmp.js ≤ ২০KB gzipCI চেক
একটা টেস্ট যা সবচেয়ে বেশি কাজে দেবে

একটা ফিক্সচার HTML পেজ — তাতে নকল Analytics, নকল Pixel, একটা iframe, একটা data-cmp="ignore" স্ক্রিপ্ট। Playwright সেটা খুলে কুকি গুনবে। এই এক টেস্ট প্রতি ডিপ্লয়ে চলবে এবং ব্লকিং ইঞ্জিনের রিগ্রেশন ধরে ফেলবে।

২৩ · বাস্তবায়নের ধাপ

এই ক্রম মেনে চললে প্রতিটা ধাপ শেষে কিছু একটা কাজ করে দেখা যাবে। প্রতিটা ধাপের “প্রমাণ” না পেলে পরের ধাপে যাওয়া হবে না।

প্রস্তুতিধাপ ০
  • Turborepo রিপো, তিন অ্যাপের কঙ্কাল
  • Postgres + Drizzle schema + প্রথম মাইগ্রেশন
  • Better Auth — সাইন আপ ও লগইন
  • CI পাইপলাইন (lint, type-check, test, size budget)

প্রমাণ: লগইন করে একটা খালি ড্যাশবোর্ড দেখা যায়।

ব্যানার দেখা যায়ধাপ ১
  • টেস্ট HTML পেজ (এটাই “ক্লায়েন্টের সাইট”)
  • cmp.js-এর প্রথম সংস্করণ — শুধু ব্যানার আঁকে (হার্ডকোড কনফিগে)
  • Accept/Decline/Preferences → ব্রাউজারে কুকি লেখে, ব্যানার লুকায়
  • রিফ্রেশে আর ব্যানার আসে না; manage pill দিয়ে ফেরত আনা যায়

প্রমাণ: টেস্ট পেজে ব্যানার আসে, পছন্দ মনে রাখে।

এই ধাপে সার্ভারের দরকারই নেই — পুরোটা ব্রাউজারে। প্রথম দিনেই চোখে দেখা ফলাফল।

🔥 ব্লকিং ইঞ্জিনধাপ ২
  • ফিক্সচার পেজে নকল ট্র্যাকার (কুকি লেখে এমন স্ক্রিপ্ট)
  • MutationObserver → নতুন এলিমেন্ট ধরা
  • block-list মিলিয়ে script/iframe/img পঙ্গু করা
  • document.cookie setter দখল
  • Accept-এ জাগানো; data-cmp="ignore" escape hatch
  • iframe প্লেসহোল্ডার
  • Google Consent Mode v2 সংকেত
  • Log Only ও Strict — দুই মোড
  • Playwright টেস্ট: আগে ০ কুকি, পরে প্রত্যাশিত

প্রমাণ: অটোমেটেড টেস্ট সবুজ + DevTools-এ চোখে দেখা।

সবচেয়ে কঠিন ধাপ। তাড়াহুড়ো নয় — এটাই প্রোডাক্ট।

সার্ভার ও multi-tenantধাপ ৩
  • sites টেবিল + site_id (UUID)
  • কনফিগ প্রকাশ (version URL) + CDN থেকে পরিবেশন
  • cmp.js script ট্যাগ থেকে site_id পড়ে
  • POST /api/consent — Zod যাচাই, Origin চেক, rate-limit
  • tenant isolation টেস্ট

প্রমাণ: দুইটা সাইট, দুইটা আলাদা কনফিগ ও লগ — কোনো মিশ্রণ নেই।

ড্যাশবোর্ডধাপ ৪
  • সাইট যোগ + Install পেজ + Verify installation
  • Banner Design (লাইভ প্রিভিউ, ৯ পজিশন, ২ লেআউট)
  • Cookie Inventory (ম্যানুয়াল যোগ, bulk, regex)
  • Consent Logs + CSV + receipt PDF
  • Settings (সব ফ্রি অপশন)
  • Dashboard + Compliance Score + Checklist (Fix it সহ)
  • Notifications
  • Cookie Declaration উইজেট
  • Retention cleanup জব

প্রমাণ: 🎯 অন্য একজন সাইন আপ করে নিজের সাইটে ব্যানার চালু করতে পারল। ফ্রি প্রোডাক্ট সম্পূর্ণ।

Scannerধাপ ৫
  • BullMQ + Redis + worker সার্ভিস
  • Playwright দিয়ে এক পেজ প্রোব (কুকি + রিকোয়েস্ট)
  • sitemap / লিংক crawl, ৫০ URL সীমা
  • known-list মিলিয়ে অটো-ক্যাটাগরি; ম্যানুয়াল ক্যাটাগরি সংরক্ষণ
  • diff + Scan History পেজ
  • known_cookies সিড ডেটা + ইন্টারনাল যোগ করার টুল

প্রমাণ: আসল সাইট স্ক্যান করে সঠিক কুকি তালিকা এলো।

Paid স্তরধাপ ৬
  • Entitlement টেবিল + সার্ভার-সাইড সীমা প্রয়োগ
  • Stripe checkout, portal, webhook
  • Scheduled scans · Geo targeting · Trust Badge · Custom CSS · Integrations
  • মাল্টি-সাইট, branding সরানো

প্রমাণ: একটা টেস্ট অ্যাকাউন্ট আপগ্রেড হলো, ফিচার খুলল, সীমা বাড়ল।

লঞ্চের প্রস্তুতিধাপ ৭
  • ক্যানারি রোলআউট + রোলব্যাক পদ্ধতি
  • Sentry, uptime, ড্যাশবোর্ড মেট্রিক
  • ব্যাকআপ + পুনরুদ্ধার মহড়া
  • ইন্টারনাল অ্যাডমিন টুল
  • ডকুমেন্টেশন, প্রাইভেসি পলিসি, DPA, শর্তাবলী
  • ল্যান্ডিং পেজ

২৪ · ফাঁদের তালিকা

#ফাঁদপ্রতিকার
স্ক্রিপ্ট দেরিতে লোড → ট্র্যাকার আগেই কুকি বসাল<head>-এর প্রথমে, async/defer নয়, ২০KB বাজেট
site_id ছাড়া কোয়েরি → এক কাস্টমার অন্যের ডেটা দেখলএকটাই tenant-aware ডেটা লেয়ার + Postgres RLS + টেস্ট
consent_logs ফুলে গিয়ে ড্যাশবোর্ড ধীরindex + partition + consent_daily সারাংশ + retention
Strict চালু করতেই ক্লায়েন্টের সাইট ভাঙলডিফল্ট Log Only, escape hatch, iframe প্লেসহোল্ডার, স্পষ্ট সতর্কবার্তা
কনফিগ ক্যাশড থাকায় সেটিংস বদল দেখা যাচ্ছে নাversion URL — নতুন version = নতুন ফাইল
হেডলেস Chrome সার্ভারের RAM শেষ করলআলাদা সার্ভিস, worker সীমা, পেজ সীমা, টাইমআউট
স্ক্যানার JS-নির্ভর সাইটে কিছুই পেল নাnetwork idle পর্যন্ত অপেক্ষা + নিচ পর্যন্ত স্ক্রল
স্ক্যান নতুন করে চালালে কাস্টমারের ম্যানুয়াল ক্যাটাগরি মুছে গেলmanual_category আলাদা কলামে, স্ক্যান কখনো ওটা লিখবে না
কাঁচা IP সেভ করে নিজেরাই আইন ভাঙাশুধু hash, salt আলাদা গোপন
১০“পুরোনো সম্মতি ফিরল” আর “এইমাত্র ক্লিক” একই ইভেন্ট → analytics ডাবলদুইটা আলাদা ইভেন্ট
১১ভুয়া সম্মতি স্প্যাম করে DB ভরানোrate-limit + Origin যাচাই + ডোমেইন ভেরিফিকেশন
১২ড্যাশবোর্ডে সমস্যা দেখায় কিন্তু ঠিক করা যায় নাপ্রতিটা চেকলিস্ট আইটেমে “Fix it”
১৩স্ক্রিপ্টের ত্রুটিতে ক্লায়েন্টের পুরো পেজ ভাঙলfail open — try/catch, ব্যর্থ হলে চুপচাপ সরে যাওয়া
১৪খারাপ রিলিজ একসাথে হাজার সাইটে গেলক্যানারি + এক-পয়েন্টার রোলব্যাক
১৫স্ক্যানার অন্যের ডোমেইনে চালানো হলোশুধু ভেরিফাইড ডোমেইন
১৬Stripe webhook দুইবার এসে দুইবার প্রয়োগ হলোidempotency key

২৫ · সিদ্ধান্ত লগ

যত সিদ্ধান্ত নেবেন, তারিখ ও কারণসহ এখানে লিখুন।

তারিখসিদ্ধান্তকেনযা বাদ দিলাম
৩১ আগ ২০২৬প্রোডাক্ট = Consent Management Platform, SaaSআইন-চালিত চাহিদা; SaaS-এর সব কঠিন অংশ এক প্রজেক্টে
৩১ আগ ২০২৬স্ট্যাক = Next.js · Postgres+Drizzle · Better Auth · BullMQ · TanStack Query · Zodকোম্পানির স্ট্যান্ডার্ড — টিমের সাহায্য ও রিভিউ পাওয়া যাবেPrisma; Redux Toolkit
৩১ আগ ২০২৬cmp.js আলাদা vanilla TS বান্ডল<20KB-এ সবার আগে পৌঁছাতে হবে; UI ফ্রেমওয়ার্ক হলে ব্লকিং রেস হেরে যেতNext.js থেকে স্ক্রিপ্ট সার্ভ করা
৩১ আগ ২০২৬ডিফল্ট = ব্যানার বন্ধ + Log Onlyঅ্যাকাউন্ট খোলার সাথে সাথে লাইভ সাইটে পপ-আপ = সবচেয়ে খারাপ প্রথম অভিজ্ঞতাডিফল্ট চালু
৩১ আগ ২০২৬বিল না দিলেও ভিজিটর-মুখী ব্যানার চলবেবন্ধ করলে ক্লায়েন্টের ট্র্যাকার সম্মতি ছাড়াই চলবে — তাকে আইনি বিপদে ফেলা হবেবকেয়ায় সেবা বন্ধ
৩১ আগ ২০২৬Scanner শেষ দিকের ধাপেসবচেয়ে ব্যয়বহুল; ব্লকিং ছাড়া প্রোডাক্ট নেই, স্ক্যান ছাড়া আছেশুরুতেই স্ক্যানার
↓ নতুন সিদ্ধান্ত এখানে যোগ করুন