অবজেক্ট স্টোরেজ বনাম ডাটাবেস ব্লব: মেটাডেটা Postgres-এ রাখুন, বাইটগুলো অবজেক্ট স্টোরেজে রাখুন, এবং ডাউনলোড দ্রুত ও খরচ পূর্বানুমানযোগ্য রাখুন।

ব্যবহারকারীর আপলোডটি শুনতে সাধারণ: একটি ফাইল নিন, সেভ করুন, পরে দেখান। এটা কয়েকজন ব্যবহারকারী এবং ছোট ফাইলের জন্য কাজ করে। কিন্তু ভলিউম বাড়লে, ফাইল বড় হলে, এবং সমস্যা দেখা দেয় এমন জায়গাগুলোতে যা আপলোড বাটনের সাথে সরাসরি সম্পর্কিত নয়।
ডাউনলোড ধীর হয়ে যায় কারণ আপনার অ্যাপ সার্ভার বা ডাটাবেস ভারি কাজ করছে। ব্যাকআপ বড় ও ধীর হয়, ফলে রিস্টোর করতে বেশি সময় লাগে ঠিক তখন যখন প্রয়োজনে দ্রুত রিস্টোর দরকার। স্টোরেজ বিল ও ব্যান্ডউইথ (ইগ্রেস) বিল বাড়তে পারে কারণ ফাইলগুলো অদক্ষভাবে সার্ভ হচ্ছিল, বহুলপ্রতি-সংস্করণ ছিল, বা ঠিকমতো ক্লিনআপ করা হচ্ছিল না।
আপনি সাধারণত যা চান তা বোরিং এবং নির্ভরযোগ্য: লোডের সময় দ্রুত ট্রান্সফার, স্পষ্ট অ্যাক্সেস নিয়ম, সিম্পল অপারেশন (ব্যাকআপ, রিস্টোর, ক্লিনআপ), এবং ব্যবহার বাড়লেও খরচ পূর্বানুমানযোগ্য থাকা।
সেখানে পৌঁছাতে, দুইটি জিনিস আলাদা করুন যেগুলো প্রায়ই একসাথে মিশে যায়:
মেটাডেটা হল ফাইল সম্পর্কে ছোট তথ্য: কে এর মালিক, কী নামে আছে, সাইজ, টাইপ, কখন আপলোড করা হয়েছে, এবং কোথায় আছে। এটি আপনার ডাটাবেসে (যেমন Postgres) থাকা উচিত কারণ আপনাকে এটিকে কোয়ারি করতে, ফিল্টার করতে, এবং ইউজার/প্রজেক্ট/পারমিশনের সাথে যোগ করতে হবে।
ফাইল বাইট হল ফাইলের আসল কনটেন্ট (ফটো, PDF, ভিডিও)। ডাটাবেস ব্লবের মধ্যে বাইট রাখা কাজ করতে পারে, কিন্তু এতে ডাটাবেস ভারী হয়ে যায়, ব্যাকআপ বড় হয়, এবং পারফরম্যান্স পূর্বাভাস করা কঠিন হয়। বাইটগুলো অবজেক্ট স্টোরেজে রাখা ডাটাবেসকে তার মূল কাজেই রাখে, আর ফাইলগুলো দ্রুত এবং সস্তায় সার্ভ হয়—এসব সিস্টেমই এ কাজের জন্য তৈরী।
যখন কেউ বলে “আপলোড ডাটাবেসে রাখুন,” তারা সাধারণত ডাটাবেস ব্লবগুলো বোঝায়: বা একটি BYTEA কলাম (রো-তে কাঁচা বাইট) অথবা Postgres "large objects" (বড় ভ্যালুগুলো আলাদাভাবে রাখে) ব্যবহার। উভয়ই কাজ করতে পারে, কিন্তু উভয়ই আপনার ডাটাবেসকে ফাইল বাইট সার্ভ করার দায়িত্ব দেয়।
অবজেক্ট স্টোরেজ হলো একটি ভিন্ন ধারণা: ফাইলটি একটি বাকেটে অবজেক্ট হিসেবে থাকে, একটি কী দিয়ে অ্যাড্রেস করা হয় (যেমন uploads/2026/01/file.pdf)। এটি বড় ফাইল, সস্তা স্টোরেজ, এবং স্ট্রিমিং ডাউনলোডের জন্য তৈরি। এটি অনেক সঙ্গোপন-পাঠও ভালভাবে হ্যান্ডেল করে, আপনার ডাটাবেস কানেকশান আটকে না রেখে।
Postgres কোয়েরি, কনস্ট্রেইন্ট, এবং ট্রানজেকশন-এ জ্বলে ওঠে। এটি সেই মেটাডেটার জন্য দুর্দান্ত—কে ফাইলের মালিক, কি টাইপ, কখন আপলোড হয়েছে, এবং ডাউনলোড করা যাবে কি না। মেটাডেটা ছোট, ইনডেক্স করা সহজ, এবং কনসিস্টেন্ট রাখা সহজ।
একটি ব্যবহারিক নিয়ম:
একটি দ্রুত সেনস চেক: যদি ব্যাকআপ, রেপ্লিকা, এবং মাইগ্রেশনগুলো ফাইল বাইটসহ কঠিন হয়ে যাবে, তাহলে বাইটগুলো Postgres-এর বাইরে রাখুন।
অধিকাংশ টিম যে সেটআপে পৌঁছায় তা সরল: বাইটগুলো অবজেক্ট স্টোরেজে রাখুন, এবং ফাইল রেকর্ড (কে মালিক, কি তা, কোথায় থাকে) Postgres-এ রাখুন। আপনার API সমন্বয় এবং অনুমোদন করে, কিন্তু বড় আপলোড বা ডাউনলোড প্রোক্সি করে না।
এটি আপনাকে তিনটি স্পষ্ট দায়িত্ব দেয়:
file_id, owner, সাইজ, content type, এবং অবজেক্ট পয়েন্টার।ওই স্থিতিশীল file_id সব কিছুই প্রধান কী হয়ে উঠে: অ্যাটাচমেন্ট রেফারেন্স করা মন্তব্য, একটি PDF-কে নির্দেশ করা ইনভয়েস, অডিট লগ, এবং সাপোর্ট টুল। ব্যবহারকারী ফাইলের নাম পরিবর্তন করতে পারে, আপনি বাকেট বদলে দিতে পারেন, কিন্তু file_id অপরিবর্তিত থাকে।
সম্ভব হলে, সংরক্ষিত অবজেক্টগুলোকে অপরিবর্তনীয় হিসেবে বিবেচনা করুন। যদি ব্যবহারকারী একটি ডকুমেন্ট প্রতিস্থাপন করে, স্থানে ওভাররাইট করার বদলে একটি নতুন অবজেক্ট (এবং সাধারণত একটি নতুন রো বা ভersion রো) তৈরি করুন। এতে ক্যাশিং সহজ হয়, "পুরাতন লিঙ্ক নতুন ফাইল দেখায়" ধরনের বিস্ময় রোধ হয়, এবং ক্লিয়ার রোলব্যাক কাহিনী থাকে।
প্রাইভেসি আগে থেকেই ঠিক করুন: ডিফল্টভাবে প্রাইভেট, কীভাবে পাবলিক হবে তা ব্যতিক্রম হিসেবে রাখুন। একটি ভালো নিয়ম হলো: ডাটাবেস কে ফাইল অ্যাক্সেস করতে পারে তা সর্বোচ্চ সত্যি হিসেবে ধরে; অবজেক্ট স্টোরেজ আপনার API যে সংক্ষিপ্ত-মেয়াদী অনুমতি দেয় তা প্রয়োগ করে।
পরিষ্কার স্প্লিটের সঙ্গে, Postgres ফাইল সম্পর্কে তথ্য রাখে, আর অবজেক্ট স্টোরেজ বাইট রাখে। এতে আপনার ডাটাবেস ছোট থাকে, ব্যাকআপ দ্রুত হয়, এবং কোয়েরি সিম্পল থাকে।
একটি বাস্তবসম্মত uploads টেবিলে কয়েকটি ফিল্ডই যথেষ্ট যেগুলো সত্যিই জিজ্ঞাসা করবে যেমন "এটি কার?", "কোথায় সংরক্ষিত?", এবং "এটি ডাউনলোড করা নিরাপদ?"।
CREATE TABLE uploads (
id uuid PRIMARY KEY,
owner_id uuid NOT NULL,
bucket text NOT NULL,
object_key text NOT NULL,
size_bytes bigint NOT NULL,
content_type text,
original_filename text,
checksum text,
state text NOT NULL CHECK (state IN ('pending','uploaded','failed','deleted')),
created_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX uploads_owner_created_idx ON uploads (owner_id, created_at DESC);
CREATE INDEX uploads_checksum_idx ON uploads (checksum);
কিছু সিদ্ধান্ত যা পরে দুর্দশা রোধ করে:
bucket + object_key ব্যবহার করুন। আপলোডের পর এটা অপরিবর্তনীয় রাখুন।pending রো ইনসার্ট করুন। শুধুমাত্র আপনার সিস্টেম অবজেক্টটি আছে এবং সাইজ (এবং আদর্শত চেকসাম) মিললে uploaded হিসেবে ফ্লিপ করুন।original_filename কেবল প্রদর্শনের জন্য রাখুন। টাইপ বা সিকিউরিটি সিদ্ধান্তে এটিকে বিশ্বাস করবেন না।আপনি যদি রিপ্লেসমেন্ট সমর্থন করেন (যেমন ব্যবহারকারী একটি ইনভয়েস পুনরায় আপলোড করছে), তাহলে একটি আলাদা upload_versions টেবিল যোগ করুন যার মধ্যে upload_id, version, object_key, এবং created_at থাকবে। এতে ইতিহাস থাকবে, ভুলগুলো রোলব্যাক করা সহজ হবে, এবং পুরনো রেফারেন্স ভেঙে পড়বে না।
আপলোডগুলো দ্রুত রাখুন API-কে সমন্বয় করানোর মাধ্যমে, বাইট হ্যান্ডল করানোর মাধ্যমে নয়। আপনার ডাটাবেস প্রতিক্রিয়াশীল থাকে, আর অবজেক্ট স্টোরেজ ব্যান্ডউইথ হিট নেয়।
শুরুতে আপলোড রেকর্ড তৈরি করুন—ক্লায়েন্ট কোন স্থানে আপলোড করবে তার upload_id, object_key, এবং সংক্ষিপ্ত-মেয়াদী আপলোড অনুমতি API থেকে ফিরে পাবে।
একটি সাধারণ ফ্লো:
pending রো তৈরি করে, প্রত্যাশিত সাইজ ও ইচ্ছুক content type সহ।upload_id এবং স্টোরেজ রেসপন্সের ক্ষেত্র (যেমন ETag) দিয়ে আপনার API-কে কল করে। সার্ভার সাইজ, চেকসাম (যদি ব্যবহার করেন), এবং content type যাচাই করে, তারপর রোকে uploaded হিসেবে মার্ক করে।failed মার্ক করুন এবং ঐ অবজেক্ট মুছে দেওয়ার অপশন রাখুন।রিট্রাই এবং ডুপ্লিকেট স্বাভাবিক। ফাইনালাইজ কলকে idempotent রাখুন: একই upload_id আবার ফাইনালাইজ করলে সাফল্য রিটার্ন করুন এবং কিছু বদলাবেন না।
রিট্রাই ও রি-আপলোডের কারণে ডুপ্লিকেট কমানোর জন্য একটি চেকসাম সংরক্ষণ করুন এবং "একই মালিক + একই চেকসাম + একই সাইজ" বিষয়টিকে একই ফাইল হিসেবে বিবেচনা করুন।
একটি ভালো ডাউনলোড ফ্লো একটি স্থির URL দিয়ে শুরু করা উচিত, যদিও বাইটগুলো অন্যত্র থাকতে পারে। ভাবুন: /files/{file_id}। আপনার API file_id দেখে Postgres-এ মেটাডেটা দেখে, পারমিশন চেক করে, তারপর ডেলিভারির উপায় ঠিক করে।
file_id দিয়ে রিকোয়েস্ট করে।uploaded আছে।পাবলিক বা সেমি-পাবলিক ফাইলের জন্য রিডাইরেক্ট সহজ এবং দ্রুত। প্রাইভেট ফাইলের জন্য প্রিসাইনড GET URL স্টোরেজকে প্রাইভেট রাখে এবং ব্রাউজারকে সরাসরি ডাউনলোড করতে দেয়।
ভিডিও ও বড় ডাউনলোডের জন্য নিশ্চিত করুন যে আপনার অবজেক্ট স্টোরেজ (এবং যেকোন প্রক্সি লেয়ার) রেঞ্জ রিকোয়েস্ট (Range হেডার) সমর্থন করে। এটি সিকিং ও রিজিউমেবল ডাউনলোড সক্ষম করে। যদি আপনি বাইটগুলো API-র মাধ্যমে ফানেল করেন, তাহলে রেঞ্জ সাপোর্ট প্রায়ই ভেঙে যায় বা ব্যয়বহুল হয়।
ক্যাশিংই গতি নিয়ে আসে। আপনার স্থির /files/{file_id} এন্ডপয়েন্ট সাধারণত নন-ক্যাশেবল হওয়া উচিত (এটি একটি অথ গেট), যেখানে অবজেক্ট স্টোরেজ রেসপন্স কন্টেন্টের ভিত্তিতে ক্যাশ করা যেতে পারে। ফাইলগুলো যদি অপরিবর্তনীয় (নতুন আপলোড = নতুন কী) হয়, তাহলে দীর্ঘ ক্যাশ লাইফ সেট করতে পারেন। ওভাররাইট করলে ক্যাশ সময় কম রাখুন বা ভার্সনড কী ব্যবহার করুন।
আপনি যদি বিশ্বজুড়ে অনেক ব্যবহারকারী বা বড় ফাইল পান তাহলে CDN সাহায্য করবে। আপনার দর্শক সংখ্যাটা কম বা এক অঞ্চলে হলে অবজেক্ট স্টোরেজই প্রায়ই যথেষ্ট এবং শুরুতে সস্তা হয়।
অপ্রত্যাশিত বিল সাধারণত ডাউনলোড এবং চর্ন থেকে আসে, কাঁচা বাইট ডাঙায় নেই।
চারটি ড্রাইভার মূল্য নির্ধারণ করে: আপনি কত স্টোর করেন, কত ঘনঘন পড়া/লিখা হয় (রিকোয়েস্ট), কত ডেটা প্রোভাইডার থেকে বাইরে যায় (ইগ্রেস), এবং আপনি কি CDN ব্যবহার করেন বারবার অরিজিন ডাউনলোড কমাতে। একটি ছোট ফাইল 10,000 বার ডাউনলোড হলে সেটি কখনোই কারো স্পর্শে না থাকা বড় ফাইলের মত ব্যয়বহুল হতে পারে।
নিয়ন্ত্রণ যা ব্যয়ের নিয়ন্ত্রণ রাখে:
লাইফসাইকেল রুলগুলো প্রায়ই সবচেয়ে সহজ জয়। উদাহরণস্বরূপ: মূল ফটো 30 দিন "হট" রাখবেন, তারপর সস্তা স্টোরেজ ক্লাসে পাঠিয়ে দিন; ইনভয়েস 7 বছর রাখুন; ব্যর্থ আপলোড পার্টস 7 দিন পর মুছে দিন। এমন সহজ রিটেনশন নীতি স্টোরেজ বাড়া আটকায়।
ডিডুপ্লিকেশন সরল হতে পারে: একটি কন্টেন্ট হ্যাশ (যেমন SHA-256) ফাইল মেটাডেটা টেবিলে রাখুন এবং প্রতিটি মালিকের জন্য ইউনিকনেস প্রয়োগ করুন। যখন ব্যবহারকারী একই PDF দুবার আপলোড করে, আপনি বিদ্যমান অবজেক্টটি পুন ব্যবহার করতে পারেন এবং কেবল একটি নতুন মেটাডেটা রো তৈরি করতে পারেন।
সবশেষে, যেখানে আপনি ইতিমধ্যেই ব্যবহারকারীর হিসাব রাখেন সেখানে Usage ট্র্যাক করুন: Postgres-এ প্রতি ব্যবহারকারী বা ওয়ার্কস্পেসের জন্য bytes_uploaded, bytes_downloaded, object_count, এবং last_activity_at রাখুন। এতে UI-তে কোটা দেখানো ও বিলিং আগেই সতর্কতা দেওয়া সহজ হয়।
আপলোড সিকিউরিটি মূলত দুই জিনিসে আসে: কে ফাইল অ্যাক্সেস করতে পারে, এবং কিছু ভুল হলে আপনার কাছে পরে কী প্রমাণ থাকবে।
স্পষ্ট এক্সেস মডেল দিয়ে শুরু করুন এবং এটি Postgres মেটাডেটায় এনকোড করুন—একটিপথে সার্ভিস জুড়ে ছড়িয়ে থাকা এক-অফ নিয়ম নয়।
অধিকাংশ অ্যাপ কভার করে এমন একটি সাধারণ মডেল:
প্রাইভেট ফাইলের জন্য কাঁচা অবজেক্ট কী এক্সপোজ করা এড়ান। সময়-সীমিত, স্কোপ-সীমিত প্রিসাইনড আপলোড ও ডাউনলোড URL ইস্যু করুন এবং সেগুলো প্রায়ই রোটেট করুন।
ট্রানজিটে এবং রেস্টে এনক্রিপশন নিশ্চিত করুন। ট্রানজিটে মানে সারাবিশ্ব HTTPS, অন্তর্ভুক্ত করে স্টোরেজে সরাসরি আপলোড। রেস্টে মানে আপনার স্টোরেজ প্রোভাইডারের সার্ভার-সাইড এনক্রিপশন, এবং ব্যাকআপ ও রেপ্লিকাও এনক্রিপ্টেড আছে তা নিশ্চিত করুন।
সুরক্ষা ও ডেটা কোয়ালিটির জন্য চেকপয়েন্ট যোগ করুন: আপলোড URL ইস্যু করার আগে টাইপ ও সাইজ ভ্যালিডেট করুন, তারপর আপলোডের পরে আবার ভ্যালিডেট করুন (বস্তুত স্টোর্ড বাইটের উপর ভিত্তি করে, শুধুমাত্র ফাইলনেম নয়)। আপনার রিস্ক প্রোফাইল প্রয়োজনে মালওয়্যার স্ক্যানিং অ্যাসিঙ্ক্রোনাসভাবে চালান এবং ফাইলটি পাশ না করা পর্যন্ত কোয়ারেন্টাইন করুন।
ঘটনা অনুসন্ধানের জন্য অডিট ফিল্ড রাখুন: uploaded_by, ip, user_agent, এবং last_accessed_at একটি বাস্তবসম্মত বেসলাইন।
ডেটা রেসিডেন্সি প্রয়োজন থাকলে স্টোরেজ রিজিয়ন সচেতনভাবে নির্বাচন করুন এবং এটি আপনার কম্পিউট পরিবেশের সাথে সামঞ্জস্য রাখুন।
অধিকাংশ আপলোড সমস্যা কাঁচা গতির নয়। এগুলো এমন ডিজাইন সিদ্ধান্ত থেকে আসে যা শুরুতে সুবিধাজনক মনে হয়, পরে বাস্তব ট্র্যাফিক, বাস্তব ডেটা, এবং বাস্তব সাপোর্ট টিকেট আসলে ব্যথা দেয়।
invoice.pdf আপলোড করে), এবং অদ্ভুত ক্যারেক্টার এজ-কেস তৈরি করে। দেখানোর জন্য মূল নাম রাখুন, কিন্তু স্টোরেজের জন্য ইউনিক কী জেনারেট করুন।একটি কনক্রিট উদাহরণ: ব্যবহারকারী যদি প্রোফাইল ফটো তিনবার প্রতিস্থাপন করে, আপনি তিনটি পুরনো অবজেক্টের জন্যই অর্থ দিতে পারেন যতক্ষণ না আপনি ক্লিনআপ ঠিক করে রাখেন। একটি নিরাপদ প্যাটার্ন হলো Postgres-এ সফট ডিলিট, তারপর ব্যাকগ্রাউন্ড জব অবজেক্ট মুছে ফেলা এবং ফলাফল রেকর্ড করা।
প্রথম বড় ফাইল আসলে, একটি ব্যবহারকারী আপলোডের মাঝখানে পেজ রিফ্রেশ করলে, বা কেউ অ্যাকাউন্ট ডিলিট করলে বাইটগুলো পিছনে থেকে যাওয়ার সময়ই বেশিরভাগ সমস্যা দেখা দেয়।
নিশ্চিত করুন আপনার Postgres টেবিল ফাইলের সাইজ, চেকসাম (ইন্টিগ্রিটি যাচাই করতে), এবং একটি স্পষ্ট স্টেট পাথ (যেমন: pending, uploaded, failed, deleted) রেকর্ড করে।
একটি লাস্ট-মাইল চেকলিস্ট:
uploaded রো তৈরি হওয়া যাবে না।একটি কনক্রিট টেস্ট: 2 GB ফাইল আপলোড করুন, 30% এ পেজ রিফ্রেশ করুন, তারপর রিজিউম করুন। তারপর ধীর কানেকশনে ডাউনলোড করে মাঝখানে সিক করে দেখুন। যদি দুই ফ্লোই অস্থির হয়, লঞ্চের আগেই ঠিক করুন।
একটি সাধারণ SaaS অ্যাপে দুই ধরনের আপলোড থাকে: প্রোফাইল ফটো (ঘনঘন, ছোট, ক্যাশ করা নিরাপদ) এবং PDF ইনভয়েস (সংবেদনশীল, প্রাইভেট রাখতে হবে)। এখানে Postgres-এ মেটাডেটা এবং অবজেক্ট স্টোরেজে বাইট রাখার সুবিধা স্পষ্ট হয়।
একটি files টেবিলের মেটাডেটা এই রকম দেখাতে পারে, কয়েকটি ক্ষেত্রে আচরণ প্রভাবিত করে:
| field | প্রোফাইল ফটো উদাহরণ | ইনভয়েস PDF উদাহরণ |
|---|---|---|
kind | avatar | invoice_pdf |
visibility | private (সাইনড URL দিয়ে সার্ভ) | private |
cache_control | public, max-age=31536000, immutable | no-store |
object_key | users/42/avatars/2026-01-17T120102Z.webp | orgs/7/invoices/INV-1049.pdf |
status | uploaded | uploaded |
size_bytes | 184233 | 982341 |
যখন ব্যবহারকারী একটি ছবি প্রতিস্থাপন করে, এটিকে ওভাররাইট না করে নতুন ফাইল হিসেবে বিবেচনা করুন। একটি নতুন রো ও নতুন object_key তৈরি করুন, তারপর ইউজার প্রোফাইলকে নতুন file_id-তে পয়েন্ট করুন। পুরানো রোকে replaced_by=<new_id> (অথবা deleted_at) দিয়ে মার্ক করুন, এবং ব্যাকগ্রাউন্ড জবের মাধ্যমে পুরানো অবজেক্ট পরে ডিলিট করুন। এতে ইতিহাস থাকে, রোলব্যাক সহজ হয়, এবং রেস কন্ডিশন এড়ায়।
সাপোর্ট ও ডিবাগিং সহজ হয় কারণ মেটাডেটা একটি গল্প বলে। যখন কেউ বলে "আমার আপলোড ব্যর্থ হয়েছে," সাপোর্ট status, একটি মানুষের পড়ার যোগ্য last_error, একটি storage_request_id বা etag (স্টোরেজ লগ ট্রেস করতে), টাইমস্ট্যাম্প (স্টল হয়েছে কি না?), এবং owner_id ও kind চেক করে (এক্সেস পলিসি ঠিক আছে কি?) দেখতে পারে।
ছোটে শুরু করুন এবং হ্যাপি-পাথে বোর্ডিং বোরিং রাখুন: ফাইল আপলোড হয়, মেটাডেটা সেভ হয়, ডাউনলোড দ্রুত হয়, এবং কিছুই হারায় না।
একটি ভাল প্রথম মাইলফলক হলো একটি ন্যূনতম Postgres টেবিল ফাইল মেটাডেটার জন্য প্লাস একটি একক আপলোড ফ্লো এবং একটি একক ডাউনলোড ফ্লো যা আপনি বোর্ডে ব্যাখ্যা করতে পারবেন। তারপর সার্ভার-সাইড ভার্সনিং, কোটা, এবং লাইফসাইকেল নিয়ম যোগ করুন।
প্রতি ফাইল টাইপের জন্য একটি স্পষ্ট স্টোরেজ নীতি নির্বাচন করুন এবং এটিকে লিখে রাখুন। উদাহরণস্বরূপ, প্রোফাইল ফটো ক্যাশেবল হতে পারে, আর ইনভয়েস প্রাইভেট এবং শুধুমাত্র সংক্ষিপ্ত-মেয়াদী ডাউনলোড URL-এর মাধ্যমে অ্যাক্সেসযোগ্য হওয়া উচিত। এক বালতি প্রিফিক্সের মধ্যে নীতিগুলো মিশিয়ে রাখলে দুর্ঘটনাজনিত এক্সপোজার ঘটে।
শুরুতেই মেট্রিক্স যোগ করুন। প্রথম দিন থেকেই যা আপনি চান তা: আপলোড ফাইনালাইজ ফেল রেট, orphan রেট (অবজেক্ট ছাড়া DB রো এবং উল্টো), ফাইল টাইপ অনুযায়ী ইগ্রেস ভলিউম, P95 ডাউনলোড লেটেন্সি, এবং গড় অবজেক্ট সাইজ।
দ্রুত প্রোটোটাইপ করতে চাইলে Koder.ai (koder.ai) এই প্যাটার্ন অনুযায়ী সম্পূর্ণ অ্যাপ জেনারেট করে (React, Go, Postgres), এবং এটি স্কিমা, এন্ডপয়েন্ট, এবং ব্যাকগ্রাউন্ড ক্লিনআপ জবগুলোর উপর দ্রুত পুনরাবৃত্তি করার সহজ উপায় হতে পারে।
তারপর, শুধু সেইগুলো যোগ করুন যেগুলো আপনি এক বাক্যে বলতে পারেন: "আমরা পুরোনো ভার্সন 30 দিন রাখি" বা "প্রতিটি ওয়ার্কস্পেস পাচ্ছে 10 GB." বাস্তব ব্যবহার না ছাড়া জটিল করবেন না।
Postgres-এ সেই মেটাডেটা রাখুন যেটি আপনাকে কোয়ারি ও সুরক্ষিতভাবে রাখতে হবে (মালিক, অনুমতি, স্টেট, চেকসাম, পয়েন্টার)। বাইটগুলো অবজেক্ট স্টোরেজে রাখুন যাতে ডাউনলোড এবং বড় ট্রান্সফার ডাটাবেস কানেকশন খেয়ালে না ফেলে বা ব্যাকআপ বাড়িয়ে না দেয়।
এটি ডাটাবেসকে ফাইল সার্ভার হিসেবেও কাজ করতে বাধ্য করে। টেবিলের আকার বাড়ে, ব্যাকআপ ও রিস্টোর ধীর হয়ে যায়, রেপ্লিকেশন লোড বাড়ে, এবং অনেক ব্যবহারকারী একসাথে ডাউনলোড করলে পারফর্ম্যান্স অপ্রত্যাশিতভাবে খারাপ হতে পারে।
হ্যাঁ। অ্যাপে এক স্থায়ী file_id রাখুন, মেটাডেটা Postgres-এ রাখুন, এবং বাইটগুলো অবজেক্ট স্টোরেজে bucket ও object_key দিয়ে অ্যাড্রেস করুন। আপনার API অনুমোদন করবে এবং সংক্ষিপ্ত-মেয়াদী আপলোড/ডাউনলোড অনুমতি দেবে—বাইটগুলো প্রোক্সি করবে না।
প্রথমে একটি pending রেকর্ড তৈরি করুন, একটি ইউনিক object_key জেনারেট করুন, তারপর ক্লায়েন্টকে সংক্ষিপ্ত-মেয়াদী অনুমতি দিয়ে সরাসরি স্টোরেজে আপলোড করতে দিন। আপলোড শেষে ক্লায়েন্ট একটি ফাইনালাইজ কল করবে যাতে সার্ভার আকার ও চেকসাম যাচাই করে এবং তারপর uploaded হিসেবে মার্ক করে।
কারণ বাস্তব আপলোডগুলো ব্যর্থ এবং রিট্রাই করে। একটি স্টেট ফিল্ড আপনাকে এমন ফাইলগুলো আলাদা করতে দেয় যেগুলো প্রত্যাশিত কিন্তু উপস্থিত নেই (pending), সম্পন্ন (uploaded), ত্রুটিপূর্ণ (failed), বা মুছে ফেলা হয়েছে (deleted)—এতে UI, ক্লিনআপ জব, এবং সাপোর্ট টুলগুলো সঠিকভাবে কাজ করে।
original_filename শুধু প্রদর্শনের জন্য রাখুন। স্টোরেজে সংঘর্ষ, অদ্ভুত ক্যারেক্টার ও নিরাপত্তা সমস্যা এড়াতে ইউনিক সংরক্ষণ কী (অften UUID-ভিত্তিক পাথ) জেনারেট করুন। UI-তে আপনি মূল নাম দেখাতে পারেন, কিন্তু স্টোরেজ পাথগুলো পরিষ্কার ও পূর্বানুমানযোগ্য রাখুন।
একটি স্থায়ী অ্যাপ URL (যেমন /files/{file_id}) কে অনুমতি গেট হিসেবে ব্যবহার করুন। Postgres-এ এক্সেস চেক করার পর রিডিরেক্ট দিন অথবা প্রাইভেট ফাইলগুলোর জন্য সংক্ষিপ্ত-মেয়াদী সাইনড GET URL প্রদান করুন যাতে ক্লায়েন্ট সরাসরি অবজেক্ট স্টোরেজ থেকে ডাউনলোড করে এবং আপনার API হট-পাথ থেকে বাইরে থাকে।
ইগ্রেস ও পুনরাবৃত্ত ডাউনলোড সাধারণত প্রধান খরচ চালক; কাচা ডিস্ক স্পেস নয়। ফাইল সাইজ সীমা ও কোটা দিন, রিটেনশন/লাইফসাইকেল নিয়ম ব্যবহার করুন, চেকসাম দিয়ে ডিডুপ্লিকেট করুন যেখানে মানে আছে, এবং ইউজেজ কাউন্টার রাখুন যাতে বিল বাড়ার আগেই সতর্কতা আসতে পারে।
দিব্যমান নীতি Postgres-এ উৎস হিসেবে রাখুন এবং স্টোরেজকে ডিফল্টভাবে প্রাইভেট রাখুন। আপলোডের আগে ও পরে টাইপ ও সাইজ যাচাই করুন, HTTPS ব্যাবহার করুন, রেস্টে এনক্রিপশন নিশ্চিত করুন, এবং ঘটনার তদন্তের জন্য uploaded_by, ip, user_agent, last_accessed_at মতো অডিট ফিল্ড রাখুন।
একটি মেটাডেটা টেবিল, একটি ডাইরেক্ট-টু-স্টোরেজ আপলোড ফ্লো, এবং একটি ডাউনলোড গেট এন্ডপয়েন্ট দিয়ে শুরু করুন; তারপর orphan অবজেক্টসমূহ ও সফট-ডিলিট রোদের জন্য ক্লিনআপ জব যোগ করুন। দ্রুত প্রোটোটাইপ করার জন্য Koder.ai (koder.ai) React/Go/Postgres স্ট্যাক থেকে কোড জেনারেট করতে সাহায্য করে, কিন্তু ওভারবিল্ড করবেন না—প্রথমে মৌলিক পথে ঠেকুন।