১ · প্রোডাক্ট সংজ্ঞা
ক্লায়েন্ট তার ওয়েবসাইটে আমাদের একটা ছোট <script> বসাবে। সেটা পেজে সবার আগে পৌঁছে ট্র্যাকারদের আটকে রাখবে, ভিজিটরকে সম্মতি জিজ্ঞেস করবে, সম্মতি পেলে ছেড়ে দেবে, আর প্রতিটা সম্মতি আমাদের ডাটাবেসে প্রমাণ হিসেবে রাখবে। পাশাপাশি ক্লায়েন্টের সাইট স্ক্যান করে বলে দেবে সেখানে আসলে কী কী কুকি ও ট্র্যাকার আছে।
৫টা ক্রিয়া — প্রোডাক্টের সবটুকু
১. SCAN → সাইটে কী কী ট্র্যাকার/কুকি আছে জানো ২. BLOCK → সম্মতির আগে ওদের ঘুম পাড়িয়ে রাখো ৩. ASK → ভিজিটরকে ব্যানার দেখিয়ে জিজ্ঞেস করো ৪. WAKE → যে ক্যাটাগরিতে হ্যাঁ, শুধু সেগুলো জাগাও ৫. LOG → কে কখন কী বলল, প্রমাণ হিসেবে লিখে রাখো
কোনো ফিচার নিয়ে সন্দেহ হলে জিজ্ঞেস করুন — এটা কি এই ৫টার কোনো একটাকে ভালো করছে? না হলে সেটা এই সংস্করণে নেই।
কী সমস্যা সমাধান করে
- ইউরোপ/ব্রিটেন/ক্যালিফোর্নিয়ার ভিজিটর এলে আইনত সম্মতি নিতে হয় — না নিলে জরিমানা।
- সাইট মালিক জানেই না তার সাইটে কয়টা কুকি বসে, কে বসায়।
- ব্যানার দেখালেই হয় না — সম্মতির আগে ট্র্যাকার চললে আইন ভাঙা হয়েই যায়।
- রেগুলেটর প্রমাণ চাইলে দেখানোর মতো রেকর্ড থাকে না।
যা আমরা দাবি করব না
“আপনি ১০০% আইনি সুরক্ষিত” — এটা বলা যাবে না। আমরা টুল দিই, আইনি পরামর্শ নয়। compliance নির্ভর করে ক্লায়েন্টের সাইট, তার ব্যবহৃত থার্ড-পার্টি টুল, অঞ্চল আর কনফিগারেশনের উপর। শর্তাবলী ও মার্কেটিং — সব জায়গায় এই ভাষা এক রাখতে হবে।
২ · ব্যবহারকারী ও ভূমিকা
| কে | কী করে | কোন অংশ ব্যবহার করে |
|---|---|---|
| ভিজিটর | ক্লায়েন্টের সাইটে আসে, ব্যানার দেখে, Accept/Decline চাপে। আমাদের অস্তিত্বই জানে না। | embed script + ব্যানার |
| সাইট মালিক | সাইন আপ করে, স্ক্রিপ্ট বসায়, ব্যানার সাজায়, লগ দেখে, টাকা দেয় | ড্যাশবোর্ড |
| এজেন্সি | এক অ্যাকাউন্টে বহু ক্লায়েন্ট সাইট চালায় | ড্যাশবোর্ড (মাল্টি-সাইট) |
| আমাদের সাপোর্ট টিম | সমস্যা তদন্ত করে, অ্যাকাউন্ট দেখে | ইন্টারনাল অ্যাডমিন (§২১) |
ভিজিটরের সংখ্যা কাস্টমারের চেয়ে হাজার গুণ বেশি। ১০০ কাস্টমার = দিনে ১০ লাখ ভিজিটর হতে পারে। তাই ভিজিটর-মুখী অংশ (script + consent API) আর কাস্টমার-মুখী অংশ (ড্যাশবোর্ড) আলাদা ডিজাইন করতে হবে। একসাথে বানালে ড্যাশবোর্ডের একটা ধীর কোয়েরি পুরো সিস্টেম বসিয়ে দেবে।
৩ · শব্দকোষ
কাজ করতে করতে ভুলে গেলে এখানে ফিরে আসুন।
ওয়েবের মৌলিক
| শব্দ | মানে | উপমা |
|---|---|---|
| Browser | Chrome/Firefox — যা ওয়েবসাইট দেখায় | রেস্টুরেন্টের খদ্দের |
| Server | ২৪ ঘণ্টা চালু কম্পিউটার, ফাইল পাঠায় | রান্নাঘর |
| HTML | পেজের কাঠামো | রেসিপির কাগজ |
| <head> | HTML-এর উপরের অদৃশ্য অংশ; স্ক্রিপ্ট এখানে বসে | রান্নার প্রস্তুতি |
| DOM | HTML থেকে ব্রাউজার যে জীবন্ত, বদলানো যায় এমন গাছ বানায় | টেবিলে সাজানো আসল খাবার |
| MutationObserver | DOM বদলালেই খবর দেওয়ার ব্রাউজার-সুবিধা | দরজার CCTV + দারোয়ান |
| iframe | এক পেজের ভেতর আরেক পেজ (YouTube, Maps) | টেবিলের উপর ছোট টেবিল |
| Tracking pixel | ১×১ অদৃশ্য ছবি; লোড হলেই সার্ভারে খবর যায় | প্লেটের নিচে লুকানো ঘণ্টা |
আমাদের ডোমেইন
| শব্দ | মানে |
|---|---|
| Cookie | ব্রাউজারে রাখা ছোট নোট: নাম + মান + মেয়াদ |
| First-party | যে সাইটে আছি সে নিজে বসিয়েছে (সাধারণত নিরীহ) |
| Third-party | বাইরের কোম্পানি বসিয়েছে (Google, Meta) — মূল সমস্যা |
| Tracker | কুকি যে বসায় — সেই স্ক্রিপ্ট / iframe / pixel |
| Consent | ভিজিটরের দেওয়া সম্মতি |
| Category | Necessary / Functional / Analytics / Marketing |
| CMP | Consent Management Platform — আমরা যেটা বানাচ্ছি |
| GDPR / CCPA | ইউরোপ / ক্যালিফোর্নিয়ার প্রাইভেসি আইন |
| Google Consent Mode v2 | Google ট্যাগগুলোকে সম্মতির অবস্থা জানানোর মানসম্মত উপায় |
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 Banner | Card ও Bar — দুই লেআউট; ৯টা পজিশন; overlay চালু/বন্ধ; border-radius; background/text/accent রং; হেডলাইন ও বর্ণনার লেখা; বাটনের লেখা — সব কোড ছাড়াই এডিটযোগ্য |
| ২ | তিন অ্যাকশন + Preferences | Accept 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 Logs | consent id, status, প্রদত্ত ক্যাটাগরি, page URL, banner version, timestamp — সার্চ ও ফিল্টারযোগ্য |
| ১০ | এক্সপোর্ট | সম্পূর্ণ রেকর্ড CSV; একক সম্মতির receipt PDF |
| ১১ | Dashboard + Compliance Score | ৭-পয়েন্ট চেকলিস্ট ও স্কোর; মোট consent; accept rate; active cookies (ক্যাটাগরিভিত্তিক); recent activity |
| ১২ | Scan History | আগের স্ক্যান — সময়, পেজ সংখ্যা, পাওয়া কুকির সংখ্যা, নতুন কুকি, ফলাফলের সারাংশ |
| ১৩ | Settings | consent mode · consent expiry · log retention · Google Consent Mode টগল · uncategorized কুকির আচরণ (সবসময় ব্লক / marketing ধরা) · ম্যানুয়াল ক্যাটাগরি মনে রাখা · manage pill দেখানো |
| ১৪ | Manage pill | ভাসমান ছোট আইকন — ভিজিটর যেকোনো সময় মত বদলাতে পারে |
| ১৫ | Retention cleanup | নির্ধারিত মেয়াদ পেরোনো consent log স্বয়ংক্রিয়ভাবে মুছে যায় |
| ১৬ | Notifications | ড্যাশবোর্ডে বিজ্ঞপ্তি (স্ক্যান শেষ, নতুন ট্র্যাকার পাওয়া গেছে ইত্যাদি) + acknowledge |
| ১৭ | Cookie Declaration | পাবলিক কুকি তালিকা — ক্লায়েন্ট তার প্রাইভেসি পলিসি পেজে বসাতে পারে |
Paid ফিচার
| # | ফিচার | বিস্তারিত |
|---|---|---|
| ১ | Scheduled automatic scans | নির্ধারিত সময়ে (দৈনিক/সাপ্তাহিক/মাসিক) নিজে নিজে স্ক্যান |
| ২ | Geo targeting | দেশ অনুযায়ী ব্যানার দেখানো বা লুকানো |
| ৩ | Integrations | Google Tag Manager · Meta Pixel · Adobe Experience Platform |
| ৪ | Trust Badge | সাইটের ফুটারে “Privacy Protected” ব্যাজ |
| ৫ | Custom CSS | ব্যানারে নিজের CSS দেওয়ার সুযোগ |
| ৬ | মাল্টি-সাইট | এক অ্যাকাউন্টে একাধিক সাইট |
| ৭ | বর্ধিত সীমা | বেশি স্ক্যান পেজ, দীর্ঘ log retention, বেশি এক্সপোর্ট |
| ৮ | Priority support | সাপোর্ট নীতি — কোড নয় |
৫ · সিস্টেমের ৪ স্তর
সবচেয়ে গুরুত্বপূর্ণ আর্কিটেকচার সিদ্ধান্ত। এই ৪টার চাহিদা সম্পূর্ণ ভিন্ন, তাই আলাদা রাখতে হবে।
| স্তর | কী করে | ট্রাফিক | ধরন | ব্যর্থ হলে |
|---|---|---|---|---|
| A · Edge / CDN | embed 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 → জাগানো। এখানে ডাটাবেস পড়া হয় না — শুধু লেখা হয়।
🟢 কাস্টমারের যাত্রা (দিনে কয়েকবার)
লগইন → ড্যাশবোর্ড → সেটিংস বদল → সেভ → নতুন কনফিগ ভার্সন প্রকাশ → স্ক্যান চালানো → লগ দেখা ও এক্সপোর্ট।
কনফিগ CDN-এ ক্যাশড থাকলে দ্রুত, কিন্তু সেটিংস বদলালে পুরোনো কনফিগ কতক্ষণ থাকবে? সমাধান: কনফিগ URL-এ version নম্বর — /c/{site_id}/v7.json। সেটিংস বদলালে version বাড়ে, নতুন URL মানে নতুন ফাইল। পুরোনোটা মুছতেই হয় না, cache purge-এর ঝামেলাও নেই।
৭ · টেকনোলজি স্ট্যাক
✅ চূড়ান্ত। ভিত্তি: কোম্পানির স্ট্যান্ডার্ড স্ট্যাক + প্রয়োজনীয় সংযোজন।
| স্তর | কী দরকার | সিদ্ধান্ত |
|---|---|---|
| embed script (cmp.js) | খুব ছোট, নির্ভরতাহীন, সব ব্রাউজারে চলে | vanilla TypeScript + Vite |
| CDN / edge | বিশ্বজুড়ে দ্রুত, সস্তা | Cloudflare |
| Consent API | write-heavy, দ্রুত | Next.js Route Handler (লজিক আলাদা ফাংশনে রাখা) |
| Admin frontend | ড্যাশবোর্ড, ফর্ম, চার্ট | Next.js (App Router) + TanStack Query |
| Admin backend | CRUD, auth, বিলিং | Next.js Route Handlers |
| Database | রিলেশনাল, বিশাল টেবিল সামলাতে পারে | PostgreSQL + Drizzle ORM |
| Validation | এক schema, দুই পাশে | Zod — packages/shared-এ |
| Queue | স্ক্যান জব সারিবদ্ধ করা | BullMQ + Redis |
| Scanner | হেডলেস ব্রাউজার | Playwright (আলাদা সার্ভিস) |
| Auth | লগইন, সেশন, টিম | Better Auth |
| Billing | সাবস্ক্রিপশন, ইনভয়েস | Stripe |
| ভেরিফিকেশন, রিপোর্ট, রিসেট | Resend | |
| File storage | CSV / 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> | type → text/plain, src → data-src |
| ২ | ইনলাইন <script> | type → text/plain |
| ৩ | <iframe> | src → data-src + প্লেসহোল্ডার দেখানো |
| ৪ | <img> (tracking pixel) | src → data-src |
| ৫ | document.cookie | setter দখল করে 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 হিসেবে ধরো — কম কড়া, কম সাইট ভাঙে
কোনো স্ক্রিপ্ট ব্লক না করার উপায় বাধ্যতামূলক: <script data-cmp="ignore">। না দিলে কাস্টমারের পেমেন্ট গেটওয়ে বা চ্যাট উইজেট ভেঙে যাবে আর দোষ আমাদের ঘাড়ে পড়বে।
ভিডিও ব্লক করলে সাদা ফাঁকা জায়গা থাকবে — ভিজিটর ভাববে সাইট ভাঙা। ওখানে একটা বাক্স দেখান: “এই কনটেন্ট দেখতে 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 নির্দেশনা) |
| ব্যানার বন্ধ করা = Decline | X চাপা মানে “হ্যাঁ” নয় |
| প্রত্যাহার যত সহজ, দেওয়াও তত সহজ | 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
}
cmp.js শুধু একটা জিনিস আনবে — এক রিকোয়েস্ট, ক্যাশড, দ্রুত। একাধিক API কল মানে ধীর, আর ধীর মানে ট্র্যাকার জিতে যায়।
১১ · ইঞ্জিন ৩ — Consent Log
এটাই প্রোডাক্টের আইনি মূল্য। রেগুলেটর এলে এটাই দেখানোর জিনিস।
| ফিল্ড | উদাহরণ | কেন লাগে |
|---|---|---|
consent_id | UUID | ভিজিটরকে চেনা, নাম না জেনেই |
site_id | UUID | 🔴 multi-tenant — কখনো বাদ দেওয়া যাবে না |
visitor_hash | sha256 | একই ভিজিটরের বারবার সম্মতি আলাদা করা |
created_at | timestamp (UTC) | কখন |
status | accepted_all / declined / custom / withdrawn | কীভাবে দিল |
categories | {analytics:true, marketing:false} | কী অনুমতি |
config_version | 7 | ⭐ কোন লেখা দেখে রাজি হয়েছিল — প্রমাণের প্রাণ |
page_url | /pricing | প্রেক্ষাপট |
country | DE | কোন আইন প্রযোজ্য |
ua_hash | sha256 | একই ডিভাইস কিনা |
প্রাইভেসি টুল বানাতে গিয়ে নিজেরাই যেন প্রাইভেসি না ভাঙি। কাঁচা 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-এ কারণ — কাস্টমার যেন কারণ দেখতে পায়
- শুধু ভেরিফাইড ডোমেইন স্ক্যান করা যাবে (§১৬) — নাহলে আমাদের স্ক্যানার অন্যের সাইটে আক্রমণের হাতিয়ার হয়ে যেতে পারে
কোড নকল করা সহজ, কিন্তু যাচাই করা কুকি-তালিকা বানাতে মাসের পর মাস লাগে। কলাম: 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)
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}.js | Cookie 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-এর বেশি লাগলে ক্লায়েন্টের সাইট ধীর মনে হবে।
১৫ · ড্যাশবোর্ড
| পেজ | কী থাকবে |
|---|---|
| Dashboard | Compliance 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 রিপোর্ট, ব্যর্থতার কারণ |
| Settings | consent mode, expiry, retention, GCM v2, uncategorized আচরণ, manual category মনে রাখা, manage pill, প্রাইভেসি লিংক; paid হলে geo, trust badge, scheduled scan |
| Install | কপি করার স্ক্রিপ্ট, বসানোর নির্দেশনা, Verify installation বাটন |
| Billing | প্ল্যান, ব্যবহারের পরিমাণ, ইনভয়েস, আপগ্রেড |
Compliance Checklist — ৭টা চেক
- Consent banner চালু আছে
- Consent mode = Strict (Log Only হলে ব্যর্থ)
- সব কুকি ক্যাটাগরাইজ করা
- Privacy policy লিংক দেওয়া
- গত ৩০ দিনে স্ক্যান হয়েছে
- Consent expiry ≤ ১৩ মাস
- Google Consent Mode v2 চালু
ক্লিক করলে ওখানেই ছোট মডাল খুলে সেটিংসটা বদলে দেবে। ইউজারকে পেজ খুঁজতে পাঠানো যাবে না।
কারণ: 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 টেবিল, একটাই চেক ফাংশন।
| সীমা | Free | Paid |
|---|---|---|
| সাইট সংখ্যা | ১ | প্ল্যান অনুযায়ী |
| স্ক্যানে সর্বোচ্চ URL | ৫০ | বেশি |
| স্ক্যান ফ্রিকোয়েন্সি | ম্যানুয়াল | + scheduled |
| Consent log retention | সীমিত | দীর্ঘ |
| এক্সপোর্ট | সীমিত | পূর্ণ |
| Branding (“Powered by”) | থাকে | সরানো যায় |
| Geo · Trust badge · Custom CSS · Integrations | — | ✔ |
| টিম মেম্বার | ১ | একাধিক |
① সীমা সার্ভারে প্রয়োগ হবে, শুধু UI-তে বাটন লুকিয়ে নয়।
② প্ল্যান ডাউনগ্রেড হলে ডেটা মোছা হবে না — শুধু অ্যাক্সেস সীমিত হবে, যেন আপগ্রেড করলেই ফিরে পায়।
③ সীমা ছাড়ালে চুপচাপ বিল বাড়ানো হবে না — কাস্টমারকে জানানো হবে, সিদ্ধান্ত তার।
১৮ · বিলিং
- Stripe Checkout দিয়ে সাবস্ক্রিপশন; Customer Portal দিয়ে কার্ড/প্ল্যান বদল ও ইনভয়েস
- Stripe webhook →
accounts.planওstatusআপডেট (এটাই সত্যের উৎস) - 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 দুই ধাপে (আগে কলাম যোগ, পরে পুরোনো বাদ)
আমাদের স্ক্রিপ্টে অপ্রত্যাশিত ত্রুটি হলে সে নিজেকে গুটিয়ে নেবে — ক্লায়েন্টের পেজ যেন স্বাভাবিক চলে। ব্যানার না আসা খারাপ, কিন্তু ক্লায়েন্টের পুরো সাইট সাদা হয়ে যাওয়া অনেক বেশি খারাপ।
২১ · অপারেশন ও সাপোর্ট
মনিটরিং — যা দেখতেই হবে
| মেট্রিক | কেন |
|---|---|
| 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 gzip | CI চেক |
একটা ফিক্সচার 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.cookiesetter দখল- Accept-এ জাগানো;
data-cmp="ignore"escape hatch - iframe প্লেসহোল্ডার
- Google Consent Mode v2 সংকেত
- Log Only ও Strict — দুই মোড
- Playwright টেস্ট: আগে ০ কুকি, পরে প্রত্যাশিত
প্রমাণ: অটোমেটেড টেস্ট সবুজ + DevTools-এ চোখে দেখা।
সবচেয়ে কঠিন ধাপ। তাড়াহুড়ো নয় — এটাই প্রোডাক্ট।
- 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 জব
প্রমাণ: 🎯 অন্য একজন সাইন আপ করে নিজের সাইটে ব্যানার চালু করতে পারল। ফ্রি প্রোডাক্ট সম্পূর্ণ।
- BullMQ + Redis + worker সার্ভিস
- Playwright দিয়ে এক পেজ প্রোব (কুকি + রিকোয়েস্ট)
- sitemap / লিংক crawl, ৫০ URL সীমা
- known-list মিলিয়ে অটো-ক্যাটাগরি; ম্যানুয়াল ক্যাটাগরি সংরক্ষণ
- diff + Scan History পেজ
- known_cookies সিড ডেটা + ইন্টারনাল যোগ করার টুল
প্রমাণ: আসল সাইট স্ক্যান করে সঠিক কুকি তালিকা এলো।
- 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 শেষ দিকের ধাপে | সবচেয়ে ব্যয়বহুল; ব্লকিং ছাড়া প্রোডাক্ট নেই, স্ক্যান ছাড়া আছে | শুরুতেই স্ক্যানার |
| ↓ নতুন সিদ্ধান্ত এখানে যোগ করুন | |||