৩০ এপ্রি, ২০২৫·8 মিনিট পড়তে

অফলাইন-প্রথম মোবাইল অ্যাপ ব্যাকগ্রাউন্ড সিঙ্ক: সংঘাত, পুনরায় চেষ্টা, ব্যবহারকারী অভিজ্ঞতা

অফলাইন-প্রথম মোবাইল অ্যাপের ব্যাকগ্রাউন্ড সিঙ্ক পরিকল্পনা করুন—স্বচ্ছ সংঘাত নিয়ম, পুনরায় চেষ্টা লজিক এবং নেটিভ Kotlin ও SwiftUI অ্যাপের জন্য সহজ pending-changes UX সহ।

অফলাইন-প্রথম মোবাইল অ্যাপ ব্যাকগ্রাউন্ড সিঙ্ক: সংঘাত, পুনরায় চেষ্টা, ব্যবহারকারী অভিজ্ঞতা

সমস্যা: ব্যবহারকারীরা অফলাইনে সম্পাদনা করে এবং বাস্তবতা বদলে যায়

কেউ একটি টাস্ক শুরু করে ভালো কানেকশনে, তারপর লিফটে ঢোকে, গুদামের কোনও কোণে যায়, বা সাবওয়েতে নামেন। অ্যাপ চলতেই থাকে, তাই তারা কাজ চালিয়ে যেতে পারে। তারা Save চাপেন, একটি নোট যোগ করেন, স্ট্যাটাস বদলান, বা নতুন রেকর্ড তৈরি করতে পারেন। সবকিছু ঠিকঠাক লাগে কারণ স্ক্রিন সাথে সাথেই আপডেট হয়।

পরে, কানেকশন ফিরে এলে অ্যাপ পটভূমিতে ক্যাচআপ করতে চেষ্টা করে। পটভূমি সিঙ্ক এখানে ব্যবহারকারীদের অবাক করতে পারে।

অ্যাপ যদি সতর্ক না হয়, একই অ্যাকশন দুইবার পাঠাতে পারে (ডুপলিকেট), অথবা সার্ভারের নতুন কোনো পরিবর্তন ব্যবহারকারীর আপডেট ওভাররাইট করে দিতে পারে (হারে যাওয়া এডিট)। কখনও কখনও অ্যাপ বিভ্রান্তিকর অবস্থা দেখায় যেমন "Saved" এবং "Not saved" একসাথে, বা একটি রেকর্ড সিঙ্কের পরে দেখা যায়, গায়েব হয়, আবার ফিরে আসে।

সংঘাতটি সহজ: একই জিনিসে দুইটি ভিন্ন পরিবর্তন হয়েছে এমন সময় যখন অ্যাপ সেগুলো মিলিয়ে নিতে পারেনি। উদাহরণ: একটি টিকেটের প্রায়ারিটি অনলাইনে একজন সহকর্মী High করেছে, আর অফলাইনে থাকা সাপোর্ট এজেন্ট একই টিকেট বন্ধ করে দিয়েছেন। যখন ফোন অন হয়, দুটো পরিবর্তনই একসাথে খাপ খায় না যতক্ষণ না একটি নিয়ম মেনে চলা হয়।

লক্ষ্যটি পারফেক্ট অফলাইন বানানো নয়। লক্ষ্যটি হলো তা পূর্বানুমেয় করা:

  • মানুষ কাজ চালিয়ে যেতে পারে তাদের কাজ হারানোর ভয় ছাড়া।
  • সিঙ্ক পরে হবে, ডুপলিকেট নয়।
  • যখন মনোযোগ দরকার, অ্যাপ স্পষ্টভাবে বলে কী ঘটেছে এবং পরবর্তী করণীয় কী।

এটি সত্য শতভাগ হাতেকলমে Kotlin/SwiftUI লিখে বানান বা AppMaster-এর মতো নো-কোড প্ল্যাটফর্মে নেটিভ অ্যাপ তৈরি করুন—কঠিন অংশটি UI উইজেট নয়। কঠিন অংশ হলো সিদ্ধান্ত নেওয়া যে ব্যবহারকারী অফলাইনে থাকাকালীন বিশ্বের পরিবর্তন হলে অ্যাপ কীভাবে আচরণ করবে।

একটি সহজ অফলাইন-প্রথম মডেল (জাগরিত শব্দ ছাড়া)

অফলাইন-প্রথম অ্যাপ ধরে নেয় ফোন মাঝে মাঝে নেটওয়ার্ক হারাবে, কিন্তু অ্যাপ ব্যবহারের যোগ্য অনুভূত হওয়া উচিত। সার্ভার পৌঁছান না-থাকলেও স্ক্রিন লোড হওয়া এবং বোতাম কাজ করা উচিত।

চারটি টার্ম বেশিরভাগ কভার করে:

  • লোকাল ক্যাশ: ডিভাইসে রাখা ডেটা যাতে অ্যাপ তৎক্ষণাৎ কিছু দেখাতে পারে।
  • সিঙ্ক কিউ: ব্যবহারকারী যখন অফলাইন (বা নেটওয়ার্ক অনিশ্চিত) ছিল তখন নেওয়া অ্যাকশনের তালিকা।
  • সার্ভারের সত্য: ব্যাকএন্ডে সংরক্ষিত সংস্করণ যা সবাই শেষ পর্যন্ত ভাগ করে।
  • সংঘাত: যখন কিউড পরিবর্তন সার্ভারের বর্তমান সংস্করণের সাথে মেলে না।

মেন্টাল মডেল হিসেবে রিড এবং রাইট আলাদা করে ভাবুন।

রিড সাধারণত সরল: সর্বোত্তম পাওয়া ডেটা দেখান (সাধারণত লোকাল ক্যাশ থেকে), তারপর নেটওয়ার্ক ফিরে এলে নীরবে রিফ্রেশ করুন।

রাইট ভিন্ন। "পুরো রেকর্ড সেভ করা"–র ওপর নির্ভর করবেন না। এটি অফলাইনে ভেঙে পড়ে।

তার বদলে, ব্যবহারকারী কী করেছে তা ছোট এন্ট্রিতে চেঞ্জ লগ হিসেবে রেকর্ড করুন। উদাহরণ: “স্ট্যাটাস Approved করা”, “কমেন্ট X যোগ করা”, “পরিমাণ 2 থেকে 3 করা”। প্রতিটি এন্ট্রি কিউতে টাইমস্ট্যাম্প ও আইডি সহ যায়। পটভূমি সিঙ্ক পরে এগুলো ডেলিভারি করতে চেষ্টা করে।

ব্যবহারকারী কাজ চালিয়ে যায় যখন পরিবর্তনগুলো pending থেকে synced হয়।

আপনি যদি AppMaster-এর মতো নো-কোড প্ল্যাটফর্ম ব্যবহার করেন, তবুও একই বিল্ডিং ব্লক চান: দ্রুত স্ক্রিনের জন্য ক্যাশড রিড, এবং ব্যবহারকারীর অ্যাকশনগুলোর একটি পরিষ্কার কিউ যেগুলো retry, merge বা conflict-এ flag করা যায়।

কোন ফিচারগুলোই অফলাইন-সাপোর্ট দরকার তা ঠিক করুন

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

ব্যবহারকারীর উদ্দেশ্য অনুযায়ী ভাবুন: বাসমেন্টে, প্লেনে বা গুদামে মানুষকে কী করতে হবে? একটি ভাল ডিফল্ট হলো প্রতিদিনকার কাজ তৈরির ও আপডেটের অ্যাকশনগুলো সাপোর্ট করা, আর যেখানে "সর্বশেষ সত্য" অত্যাবশ্যক সেখানে অনলাই-ই প্রয়োজন বলেই ব্লক করা।

অফলাইন-ফ্রেন্ডলি অ্যাকশনের যুগোপযোগী তালিকায় সাধারণত কোর রেকর্ড তৈরি ও এডিট (নোট, টাস্ক, ইনস্পেকশন, টিকেট), ড্রাফট মন্তব্য, ফটো সংযুক্তি (লোকালি রাখা, পরে আপলোড) থাকে। ডিলিটও কাজ করতে পারে, তবে সার্ভারে কনফার্ম না হওয়া পর্যন্ত আনডো উইন্ডোর সাথে সফট ডিলিট বেশি নিরাপদ।

এখন সিদ্ধান্ত নিন কী রিয়েল-টাইম থাকা দরকার কারণ ঝুঁকি বেশি। পেমেন্ট, পারমিশন পরিবর্তন, অ্যাপ্রুভাল এবং সংবেদনশীল ডেটা সাধারণত কানেকশন দাবি করে। যদি সার্ভার চেক না করলে অ্যাকশন সঠিক কি না বোঝা না যায়, অফলাইন অনুমতি দেবেন না—পরিষ্কার "কানেকশন দরকার" বার্তা দেখান, ধোঁয়াশা বা রহস্যময় এরর নয়।

তারতম্য নির্ধারণ করুন কিভাবে ডেটা "তাজা" হতে হবে। "অফলাইন" বাইনারি নয়। নির্ধারণ করুন ডেটা কতটা স্টেল হওয়া যাবে: মিনিট, ঘণ্টা, বা "পরবর্তী অ্যাপ ওপেন"। UI-তে সাধারণ ভাষায় বলুন, যেমন "সর্বশেষ আপডেট ২ ঘণ্টা আগে" এবং "অনলাইনে এসে সিঙ্ক হচ্ছে"।

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

AppMaster-এ আপনি যদি বানান, এই সিদ্ধান্ত ডেটা ও বিজনেস রুল মডেল করতে সাহায্য করে যাতে অ্যাপ নিরাপদ ড্রাফটগুলো অফলাইনে রাখে আর ঝুঁকিপূর্ণ অ্যাকশন অনলাইনে রাখে।

সিঙ্ক কিউ ডিজাইন: প্রতিটি পরিবর্তনের জন্য কী সংরক্ষণ করবেন

ব্যবহারকারী অফলাইনে কাজ করলে ডেটাবেস "সিঙ্ক" করার চেষ্টা করবেন না। ব্যবহারকারীর অ্যাকশনগুলো সিঙ্ক করুন। একটি পরিষ্কার অ্যাকশন কিউ পটভূমি সিঙ্কের মেরুদণ্ড এবং সমস্যা হলে এটিই বোঝায় কেন কি ঘটছে।

অ্যাকশনগুলো ছোট এবং মানুষের জন্য অর্থপূর্ণ রাখুন—যা ব্যবহারকারী বাস্তবে করেছে তার সাথে মেলে:

  • একটি রেকর্ড তৈরি
  • নির্দিষ্ট ক্ষেত্র(গুলি) আপডেট করা
  • স্ট্যাটাস বদলানো (submit, approve, archive)
  • ডিলিট (সার্ভারে নিশ্চিত হওয়া পর্যন্ত সফট ডিলিট ভাল)

ছোট অ্যাকশন ডিবাগ করা সহজ। সাপোর্টকে “Changed status Draft -> Submitted” পড়ে বোঝা অনেক সহজ বনাম একটি বিশাল JSON ব্লব দেখা।

প্রতিটি কিউড অ্যাকশনের জন্য পর্যাপ্ত মেটাডেটা রাখুন যাতে তা নিরাপদে পুনরায় চলানো যায় এবং সংঘাত ধরা যায়:

  • রেকর্ড আইডেন্টিফায়ার (এবং নতুন রেকর্ডের জন্য একটি অস্থায়ী লোকাল আইডি)
  • অ্যাকশন টাইমস্ট্যাম্প ও ডিভাইস আইড
  • রেকর্ডের প্রত্যাশিত সংস্করণ (অথবা শেষ জানা আপডেট সময়)
  • পে-লোড (পরিবর্তিত ক্ষেত্রগুলো ও সম্ভব হলে পুরনো মান)
  • আইডেম্পোটেন্সি কী (একটি ইউনিক অ্যাকশন আইডি যাতে রিট্রাই-এ ডুপলিকেট না হয়)

এই প্রত্যাশিত সংস্করণই সততা পূর্ণ সংঘাত হ্যান্ডলিংয়ের চাবিকাঠি। যদি সার্ভারের সংস্করণ বদলে যায়, আপনি থামতে পারেন এবং সিদ্ধান্ত নেওয়ার জন্য ইউজারকে জিজ্ঞাসা করতে পারেন, কোনো কিছু গোপনে ওভাররাইট না করে।

কিছু অ্যাকশন একসাথে প্রয়োগ করা দরকার কারণ ব্যবহারকারী সেগুলোকে এক পদক্ষেপ হিসেবে দেখে। উদাহরণ: “অর্ডার তৈরি” এবং “তিনটি লাইন আইটেম যোগ” একসাথে সফল বা ব্যর্থ হওয়া উচিত। একটি গ্রুপ আইডি (বা ট্রানজ্যাকশন আইডি) রাখুন যাতে সিঙ্ক ইঞ্জিন সেগুলো একসাথে পাঠাতে পারে এবং সবই commit হয় বা সবই pending থাকে।

হাতেকলমে বানানো হোক বা AppMaster-এ, লক্ষ্য একই: প্রতিটি পরিবর্তন একবার রেকর্ড হয়, নিরাপদে পুনরায় চালানো যায়, এবং যখন কিছু মেলে না তখন তা ব্যাখ্যাযোগ্য থাকে।

ব্যবহারকারীদের বুঝিয়ে বলতে যোগ্য সংঘাত সমাধান নীতিমালা

সংঘাতগুলো পূর্বানুমেয় করুন
সংস্করণ চেক ও সংঘাত নিয়ম যোগ করুন—পরীক্ষাযোগ্য ব্যবসায়িক প্রক্রিয়া হিসেবে।
এখন তৈরি করুন

সংঘাত স্বাভাবিক। লক্ষ্য হলো এগুলোকে বিরল, নিরাপদ এবং হলে সহজে বোঝার যোগ্য রেখে দেওয়া।

একটি সংঘাত ঘটে কখন: অ্যাপ একটা পরিবর্তন পাঠায়, সার্ভার বলায়, “এই রেকর্ডটি আপনি যে ভার্শনে সম্পাদনা শুরু করেছিলেন তা আর নেই।” এই কারণেই ভার্সনিং গুরুত্বপূর্ণ।

প্রতিটি রেকর্ডে দুইটি মান রাখুন:

  • সার্ভার ভার্সন (সার্ভারের বর্তমান সংস্করণ)
  • প্রত্যাশিত ভার্সন (যা ফোনটি মনে করছিল এটি সম্পাদনা করছিল)

যদি প্রত্যাশিত ভার্সন মিলে যায়, আপডেট গ্রহণ করুন এবং সার্ভার ভার্সন বাড়িয়ে দিন। না হলে আপনার সংঘাত নিয়ম প্রয়োগ করুন।

প্রতিটি ডেটা টাইপের জন্য একটি নিয়ম বেছে নিন (সবকিছুর জন্য এক নিয়ম নয়)

ভিন্ন ডেটার ভিন্ন প্রয়োজন। একটি স্ট্যাটাস ফিল্ড লম্বা নোটের মত নয়।

ব্যবহারকারীরা যেগুলো সহজে বুঝে সেগুলো হলো:

  • শেষ লেখাটি জিতবে (Last write wins): কম ঝুঁকির ফিল্ডের জন্য ঠিক আছে, যেমন ভিউ প্রেফারেন্স।
  • ফিল্ড মিশ্রিত করা (Merge fields): যখন ফিল্ডগুলো স্বাধীন (স্ট্যাটাস বনাম নোট) তখন ভাল।
  • ব্যবহারকারীকে জিজ্ঞাসা করুন: উচ্চ-ঝুঁকির এডিটের জন্য যেমন মূল্য, পারমিশন, বা টোটাল।
  • সার্ভার জিতবে এবং কপি রাখুন: সার্ভার মান রাখুন, কিন্তু ব্যবহারকারীর এডিট ড্রাফট হিসেবে রাখুন যাতে তারা পরে পুনরায় প্রয়োগ করতে পারে।

AppMaster-এ এই নিয়মগুলো ভিজ্যুয়াল লজিকে ভালভাবে ম্যাপ করে: ভার্সন চেক করুন, ফিল্ড তুলনা করুন, তারপর পথ বেছে নিন।

ডিলিট কিভাবে আচরণ করবে তা নির্ধারণ করুন (অথবা আপনি ডেটা হারাবেন)

ডিলিট জটিল। রেকর্ড মুছে ফেলার বদলে একটি টুম্বস্টোন ("deleted" মার্কার) ব্যবহার করুন। তারপর সিদ্ধান্ত নিন যদি কেউ অফলাইনে এমন একটি রেকর্ড এডিট করে যা অন্যত্র মুছে ফেলা হয়েছে কী হবে।

একটি পরিষ্কার নিয়ম: "ডিলিট জিতে, কিন্তু আপনি পুনরুদ্ধার করতে পারবেন।" উদাহরণ: একজন সেলসপারসন অফলাইনে একটি কাস্টমার নোট এডিট করেন, কিন্তু একজন অ্যাডমিন সেই কাস্টমার মুছে দেয়। সিঙ্কে গেলে অ্যাপ দেখায়: "কাস্টমার মুছে ফেলা হয়েছে। আপনার নোট প্রয়োগ করতে পুনরুদ্ধার করবেন কি?" এটি নীরব ক্ষতি আটকায় এবং নিয়ন্ত্রণ ব্যবহারকারীর হাতে রাখে।

রিট্রাই ও ব্যর্থ অবস্থাবলী: পূর্বানুমেয় রাখুন

যখন সিঙ্ক ব্যর্থ হয়, বেশিরভাগ ব্যবহারকারী কেন ব্যর্থ তা জানতে চায় না। তারা জানতে চায় তাদের কাজ নিরাপদ কি না এবং পরবর্তী কী হবে। একটি পূর্বানুমেয় স্টেট মডেল আতঙ্ক ও সাপোর্ট টিকিট কমায়।

একটি ছোট, দৃশ্যমান স্ট্যাটাস মডেল দিয়ে শুরু করুন এবং স্ক্রীন জুড়ে সঙ্গত রাখুন:

  • Queued: ডিভাইসে সেভ করা, নেটওয়ার্কের জন্য অপেক্ষমান
  • Syncing: এখন পাঠানো হচ্ছে
  • Sent: সার্ভার দ্বারা কনফার্মড
  • Failed: পাঠানো যায়নি, পুনরায় চেষ্টা করবে বা মনোযোগ চাইবে
  • Needs review: পাঠানো হয়েছে কিন্তু সার্ভার প্রত্যাখ্যান করেছে বা ফ্ল্যাগ করেছে

রিট্রাই ব্যাটারি ও ডেটার প্রতি নম্র হওয়া উচিত। প্রথমে দ্রুত রিট্রাই দিন (সংক্ষিপ্ত সিগনাল ড্রপ ধরার জন্য), তারপর ধীরে ধীরে কমান। 1 মিনিট, 5 মিনিট, 15 মিনিট, তারপর ঘন্টা ভিত্তিক ব্যাকঅফ সহজে বোঝায়। আর অর্থহীন এভাবে পুনরায় চেষ্টা করবেন না (যেমন একটি অবৈধ পরিবর্তন)।

ত্রুটিগুলো আলাদা ভাবে হ্যান্ডেল করুন, কারণ পরবর্তী কাজ ভিন্ন হবে:

  • অফলাইন / নেটওয়ার্ক নেই: কিউতে থাকুক, অনলাইনে এলে রিট্রাই করবে
  • টাইমআউট / সার্ভার অনুপলব্ধ: failed চিহ্নিত করে ব্যাকঅফ দিয়ে স্বয়ংক্রিয় রিট্রাই
  • Auth মেয়াদ উত্তীর্ণ: সিঙ্ক থামিয়ে ব্যবহারকারীকে আবার সাইন ইন করতে বলুন
  • ভ্যালিডেশন ব্যর্থ (ভুল ইনপুট): needs review, ঠিক কী ঠিক করতে হবে দেখান
  • সংঘাত: needs review, আপনার সংঘাত নিয়মে পাঠান

আইডেম্পোটেন্সি রিট্রাইকে নিরাপদ রাখে। প্রতিটি পরিবর্তনের একটি ইউনিক অ্যাকশন আইডি (সাধারণত UUID) থাকা উচিত যা রিকোয়েস্টের সাথে পাঠানো হয়। অ্যাপ যদি একই পরিবর্তন পুনরায় পাঠায়, সার্ভার আইডি দেখে একই ফলাফল ফেরত দেয় যাতে ডুপলিকেট তৈরি না হয়।

উদাহরণ: একজন টেকনিশিয়ান অফলাইনে একটি সম্পন্ন কাজ সেভ করেন, তারপর লিফটে ঢুকেন। অ্যাপ আপডেট পাঠায়, টাইমআউট হয়, পরে রিট্রাই করে। অ্যাকশন আইডি থাকলে দ্বিতীয়বার পাঠানো নিরপেক্ষ। না হলে আপনি ডুপলিকেট "completed" ইভেন্ট পেতে পারেন।

AppMaster-এ এই স্টেট ও নিয়মগুলোকে সিঙ্ক প্রসেসে ফার্স্ট-ক্লাস ক্ষেত্র হিসেবে বিবেচনা করুন যাতে আপনার Kotlin ও SwiftUI অ্যাপগুলো সব জায়গায় একইভাবে আচরণ করে।

পেন্ডিং পরিবর্তনের UX: ব্যবহারকারী কী দেখে ও কী করতে পারে

চেকলিস্টটি বাস্তবে লাগান
এই পোস্টের চেকলিস্টকে কাজ করা অ্যাপ ফ্লোতে রূপান্তর করুন—ঘন্টার মধ্যে ডেমো দেখান।
এখনই শুরু করুন

মানুষরা অফলাইনে ব্যবহার করতে নিরাপদ বোধ করা উচিত। ভাল "পেন্ডিং পরিবর্তন" UX শান্ত ও পূর্বানুমেয়: এটি জানায় কাজ ডিভাইসে সেভ আছে এবং পরবর্তী ধাপ স্পষ্ট করে।

একটি সূক্ষ্ম নির্দেশক ওয়ার্নিং ব্যানারের চেয়ে ভাল। উদাহরণ: হেডারে একটি ছোট "Syncing" আইকন দেখান, অথবা যেখানে এডিট হচ্ছে সেই স্ক্রিনে নীরবে "3 pending" লেবেল। বাস্তব ঝুঁকির জন্য ভয়ঙ্কর রঙ রাখুন (যেমন "আপলোড করা যায় না কারণ আপনি সাইন আউট করেছেন")।

ব্যবহারকারীদের একটি জায়গা দিন যেখানে তারা সবকিছু বুঝতে পারে। একটি সহজ Outbox বা Pending changes স্ক্রীন আইটেমগুলো তালিকাভুক্ত করতে পারে সাধারণ ভাষায় যেমন "টিকিট 104-এ কমেন্ট যোগ করা হয়েছে" বা "প্রোফাইল ফটো আপডেট করা হয়েছে।" এই স্বচ্ছতা আতঙ্ক কমায় ও সাপোর্ট টিকিট কমায়।

ব্যবহারকারীরা কী করতে পারবে

বেশিরভাগ মানুষ কয়েকটি কাজই করবে, এবং তা অ্যাপ জুড়ে সঙ্গত হওয়া উচিত:

  • এখনি Retry করা
  • আবার সম্পাদনা করা (নতুন একটি পরিবর্তন তৈরি করে)
  • লোকাল পরিবর্তন বাতিল করা
  • বিবরণ কপি করা (সমস্যা রিপোর্টে কাজে লাগবে)

স্ট্যাটাস লেবেলগুলি সরল রাখুন: Pending, Syncing, Failed। যখন কিছু ব্যর্থ হয়, মানব সম্মতিতে ব্যাখ্যা দিন: "আপলোড করা যায়নি। ইন্টারনেট নেই।" বা "রিজেক্ট করা হয়েছে: এই রেকর্ডে কেউ অন্যের দ্বারা পরিবর্তন করা হয়েছে।" এরর কোড এড়িয়ে চলুন।

পুরো অ্যাপ ব্লক করবেন না

শুধুমাত্র সেই কাজগুলো ব্লক করুন যেগুলো সত্যিই অনলাইন থাকা ছাড়া সম্ভব নয়, যেমন "Stripe দিয়ে পেমেন্ট" বা "নতুন ইউজার ইনভাইট করা"। বাকি সবকিছু কাজ করা উচিত, সাম্প্রতিক ডেটা দেখা ও নতুন ড্রাফট তৈরি করাও সহ।

বাস্তবিক একটি ফ্লো: একজন ফিল্ড টেকনিশিয়ান বাসমেন্টে একটি কাজের রিপোর্ট এডিট করে। অ্যাপ দেখায় "1 pending" এবং তারা কাজ চালিয়ে যেতে পারে। পরে এটি "Syncing" হয়ে যায়, তারপর অটোম্যাটিক ক্লিয়ার হয়। ব্যর্থ হলে রিপোর্টটি আছে, "Failed" হিসেবে মার্ক করা, একসারি "Retry now" বটন আছে।

আপনি যদি AppMaster-এ বানান, প্রতিটি রেকর্ডের অংশ হিসেবে এই স্টেটগুলো মডেল করুন (pending, failed, synced) যাতে UI কোনো স্পেশাল-কেস স্ক্রিন ছাড়া সব জায়গায় প্রভাব ফেলতে পারে।

অফলাইন অবস্থায় অথেনটিসিটি, পারমিশন ও নিরাপত্তা

ভিজ্যুয়ালি আপনার সিঙ্ক কিউ তৈরি করুন
কাস্টম গ্লু কোড ছাড়া ভিজ্যুয়াল লজিকে সিঙ্ক কিউ ও রিট্রাই মডেল করুন।
AppMaster চেষ্টা করুন

অফলাইন মোড আপনার সিকিউরিটি মডেল বদলায়। ব্যবহারকারী কানেকশন না থাকলেও অ্যাকশন নিতে পারে, কিন্তু সার্ভারই এখনও সত্যের উৎস। প্রতিটি কিউড পরিবর্তনকে "অনুরোধ করা হয়েছে", না যে তা "অনুমোদিত"—এরূপভাবে বিবেচনা করুন।

অফলাইনে লগইন মেয়াদ শেষ হওয়া

টোকেনের মেয়াদ শেষ হয়। সেটি অফলাইনে হলে ব্যবহারকারীকে এডিট করতে দিন এবং সেগুলো pending হিসেবে রাখুন। সার্ভার নিশ্চিতকরণ দাবি করে এমন অ্যাকশনগুলো সমাপ্ত মনে করবেন না। পাসিং-স্টেট পর্যন্ত রাখুন যতক্ষণ না সফল অথ রিফ্রেশ হয়।

অ্যাপ অনলাইন হলে প্রথমে নীরবে একটি রিফ্রেশ চেষ্টা করুন। যদি ব্যবহারকারীর আবার সাইন ইন করতে বলা দরকার হয়, একবার বলুন, তারপর সিঙ্ক স্বয়ংক্রিয়ভাবে চালু করুন।

পুনঃলগইন হলে প্রতিটি কিউড আইটেম পুনঃমান্য করুন। ব্যবহারকারীর পরিচয় বদলে যেতে পারে (শেয়ার করা ডিভাইস), ও পুরনো এডিট ভুল অ্যাকাউন্টের অধীনে সিঙ্ক করা যাবে না।

পারমিশন পরিবর্তন ও নিষিদ্ধ অ্যাকশন

পারমিশন অফলাইনে থাকা অবস্থায় বদলে যেতে পারে। এমন একটি এডিট যা গতকাল অনুমোদিত ছিল আজ নিষিদ্ধ হতে পারে—এটি স্পষ্টভাবে হ্যান্ডেল করুন:

  • প্রতিটি কিউড অ্যাকশনের জন্য সার্ভার-সাইডে পারমিশন পুনঃচেক করুন
  • যদি নিষিদ্ধ, ঐ আইটেম থামান এবং পরিষ্কার কারণ দেখান
  • ব্যবহারকারীর লোকাল এডিট রাখুন যাতে তারা কপি করতে পারে বা অ্যাক্সেস অনুরোধ করতে পারে
  • “forbidden” এররগুলির জন্য পুনরায় অপ্রয়োজনীয় রিট্রাই এড়িয়ে চলুন

উদাহরণ: একজন সাপোর্ট এজেন্ট প্লেনে একটি কাস্টমার নোট অফলাইনে এডিট করেন। রাতভর তাদের রোল মুছে ফেলা হয়। সিঙ্ক চলার সময় সার্ভার আপডেট প্রত্যাখ্যান করে। অ্যাপ দেখাবে "আপলোড করা যাবে না: আপনার আর অ্যাক্সেস নেই" এবং নোট লোকাল ড্রাফট হিসেবে রাখবে।

সংবেদনশীল ডেটা অফলাইনে রাখা

স্ক্রীন রেন্ডার ও কিউ পুনঃচালনার জন্য প্রয়োজনীয় ন্যূনতম ডেটাই সংরক্ষণ করুন। অফলাইন স্টোরেজ এনক্রিপ্ট করুন, সিক্রেটস ক্যাশ করা এড়িয়ে চলুন, এবং লগআউটের জন্য স্পষ্ট নিয়ম রাখুন (উদাহরণ: লোকাল ডেটা মুছে দিন, অথবা ব্যবহারকারীর স্পষ্ট সম্মতি নিলে কেবল ড্রাফট রাখুন)। AppMaster দিয়ে তৈরির ক্ষেত্রে তার authentication মডিউল দিয়ে শুরু করুন এবং কিউ এমনভাবে ডিজাইন করুন যাতে উপস্থিত সেশন না থাকলে পরিবর্তন পাঠায় না।

সাধারণ ফাঁদগুলো যা কাজ হারানো বা ডুপল রেকর্ড তৈরি করে

অধিকাংশ অফলাইন বাগ জটিল নয়। সেগুলো কয়েকটি ছোট সিদ্ধান্ত থেকেই আসে যা পরিপূর্ণ Wi‑Fi-তে পরীক্ষায় ক্ষুদ্র মনে হয়, পরে বাস্তব কাজে ভেঙে পড়ে।

একটি সাধারণ ব্যর্থতা হলো নীরবে ওভাররাইট। যদি অ্যাপ পুরোনো সংস্করণ আপলোড করে এবং সার্ভার তা চেক না করে গ্রহণ করে, আপনি কেউ অন্যকারো নতুন এডিট মুছে দিতে পারেন এবং কেউ টের পায় না যতক্ষণ খুব দেরি হয়। ভার্সন নম্বর (অথবা "last updated" স্টাম্প) দিয়ে সিঙ্ক করুন এবং সার্ভার এগিয়ে গেলে ওভাররাইট করা থেকে বিরত থাকুন—তার ফলে ব্যবহারকারী স্পষ্ট সিদ্ধান্ত নিতে পারে।

আরেকটি ফাঁদ হলো রিট্রাই স্টর্ম। ফোন যখন দুর্বল সংযোগ পায়, অ্যাপটি প্রতিটি কয়েক সেকেন্ডে ব্যাকএন্ডকে হামলা করতে পারে, ব্যাটারি খায় এবং ডুপলিকেট রাইট তৈরি করে। রিট্রাই শান্ত হওয়া উচিত: প্রতিটি ব্যর্থতার পরে ধীরে ধীরে কমান এবং সামান্য র‍্যান্ডমনেস যোগ করুন যাতে হাজার হাজার ডিভাইস একই সময়ে রিট্রাই না করে।

যে ভুলগুলো সবচেয়ে বেশি কাজ হারানো বা ডুপল করে:

  • প্রতিটি ব্যর্থতাকে "নেটওয়ার্ক" ধরার ভুল: স্থায়ী ত্রুটি (ভুল ডেটা, অনুপস্থিত পারমিশন) আলাদা করুন অস্থায়ী ত্রুটির (টাইমআউট) থেকে।
  • সিঙ্ক ব্যর্থতাগুলো লুকানো: মানুষরা না দেখলে কাজটি পুনরায় করে এবং দুইটি রেকর্ড তৈরি করে।
  • একই পরিবর্তন দুইবার পাঠানো ছাড়া সুরক্ষা নেই: প্রতিবারই ইউনিক রিকোয়েস্ট আইডি সংযুক্ত করুন যাতে সার্ভার ডুপলিকেশন চিনতে পারে।
  • পাঠ করে টেক্সট ফিল্ড অটোমেটিক মিশ্রিত করা: যদি আপনি স্বয়ংক্রিয়ভাবে মিশ্রিত করেন, ফলাফলটি পর্যালোচনার সুযোগ দিন যখন তা গুরুত্বপূর্ণ।
  • অফলাইনে রেকর্ড তৈরি করে স্থিতিশীল ID না থাকা: একটি অস্থায়ী লোকাল ID ব্যবহার করুন এবং আপলোডের পরে তা সার্ভার আইডির সাথে ম্যাপ করুন যাতে পরে এডিট ভুল রেকর্ডে না জমা হয়।

দ্রুত উদাহরণ: একজন ফিল্ড টেকনিশিয়ান অফলাইনে একটি নতুন "Site Visit" তৈরি করেন, তারপর কনেকশনে ফিরে আসার আগে এটিতে দুইবার এডিট করেন। যদি ক্রিয়েট কল রিট্রাই হয়ে দুটি সার্ভার রেকর্ড তৈরি করে, পরে হওয়া এডিটগুলো ভুল রেকর্ডে লাগবে। স্থিতিশীল ID ও সার্ভার-সাইড ডেডুপিং এটিকে প্রতিরোধ করে।

AppMaster-এ এগুলো একই রকম: যে পার্থক্য আছে তা কই করা হয়—আপনার সিঙ্ক লজিক, ডেটা মডেল এবং স্ক্রিনগুলোতে যেগুলো "failed" বনাম "sent" দেখায় সেগুলোতে।

উদাহরণ দৃশ্য: একই রেকর্ড দুইজন সম্পাদনা করে

অফলাইন কাজের জন্য ডেটা মডেল করুন
PostgreSQL-প্রথম স্টাইলে আপনার ডেটা মডেল ডিজাইন করুন এবং অফলাইনে ড্রাফট সঙ্গত রাখুন।
প্রজেক্ট শুরু করুন

একজন ফিল্ড টেকনিশিয়ান Maya একটি "Job #1842" টিকেট বাসমেন্টে আপডেট করছেন, সিগনাল নেই। তিনি স্ট্যাটাস "In progress" থেকে "Completed" করেন এবং নোট যোগ করেন: "ভালভ বদলানো, টেস্ট OK।" অ্যাপ তা তৎক্ষণাত সেভ করে এবং পেন্ডিং দেখায়।

উপরতলে, তার সহকর্মী Leo অনলাইনে একই কাজই সময়ে এডিট করেন। তিনি শিডিউল সময় বদলান এবং কাজটা অন্য টেকনিশিয়ানকে অ্যাসাইন করেন—কারণ কাস্টমার একটি আপডেট দিয়েছিল।

Maya যখন সিগনাল পায়, পটভূমি সিঙ্ক নীরবে শুরু হয়। একটি পূর্বানুমেয়, ব্যবহারকারী-বন্ধুভাবাপন্ন ফ্লোতে কী হয়:

  1. Maya-র পরিবর্তন এখনও সিঙ্ক কিউতে আছে (জব আইডি, পরিবর্তিত ক্ষেত্র, টাইমস্ট্যাম্প, এবং তিনি যে রেকর্ড ভার্সন দেখেছিলেন)।
  2. অ্যাপ আপলোড চেষ্টা করে। সার্ভার বলে: "এই জবটি আপনার ভার্সনের পরে আপডেট করা হয়েছে" (সংঘাত)।
  3. আপনার সংঘাত নিয়ম চালায়: স্ট্যাটাস ও নোট মিশানো যায়, কিন্তু অ্যাসাইনমেন্ট সার্ভারের পরের পরিবর্তন জিতবে।
  4. সার্ভার মিশ্রিত ফলাফল গ্রহণ করে: status = "Completed" (Maya), note যোগ করা (Maya), assigned technician = Leo-এর পরিবর্তন (Leo)।
  5. Maya-র অ্যাপটি স্পষ্ট ব্যানারসহ পুনরায় খুলে দেয়: "সিঙ্ক হয়েছে এবং আপডেট এসেছে। অ্যাসাইনমেন্ট আপনার অফলাইনের সময় বদলেছে।" একটি ছোট "Review" একশন দেখায় কী পরিবর্তিত।

এখন একটি ব্যর্থতার মুহূর্ত যোগ করুন: Maya-র লগইন টোকেন অফলাইনে মেয়াদ উত্তীর্ণ হয়ে যায়। প্রথম সিঙ্ক চেষ্টা "Sign in required" দিয়ে ব্যর্থ হয়। অ্যাপ তার এডিটগুলো রাখে, সেগুলোকে "Paused" চিহ্ন দেয় এবং একটি সাদাসিধে প্রম্পট দেখায়। তিনি সাইন ইন করার পরে সিঙ্ক স্বয়ংক্রিয়ভাবে আবার চালু হয়—কিছুই পুনরায় টাইপ করতে হয়নি।

যদি কোনো ভ্যালিডেশন সমস্যা থাকে (উদাহরণ: "Completed" হওয়ার জন্য একটি ছবি আবশ্যক), অ্যাপ অনুমান করবে না। এটি আইটেমটিকে "Needs attention" হিসেবে চিহ্নিত করবে, ঠিক কী যোগ করতে হবে তা বলবে, তারপর পুনরায় সাবমিট করতে দেবে।

AppMaster-এর মতো প্ল্যাটফর্ম এখানে সাহায্য করে কারণ আপনি কিউ, সংঘাত নিয়ম, এবং pending-state UX ভিজ্যুয়ালি ডিজাইন করতে পারেন, পাশাপাশি নেটিভ Kotlin ও SwiftUI অ্যাপ জেনারেট করতে পারেন।

দ্রুত চেকলিস্ট ও পরবর্তী ধাপ

অফলাইন সিঙ্ককে একটি ইন্ড-টু-ইন্ড ফিচার হিসেবে টেস্ট করুন, কিছুর ভাঁজ নয়। লক্ষ্য সহজ: ব্যবহারকারীরা কখনও ভাববে না তাদের কাজ সেভ হয়েছে কিনা, এবং অ্যাপ বিস্ময়কর ডুপলিকেট তৈরি করবে না।

ভিত্তি নিশ্চিত করার জন্য একটি সংক্ষিপ্ত চেকলিস্ট:

  • সিঙ্ক কিউ ডিভাইসে সংরক্ষিত আছে, এবং প্রতিটি পরিবর্তনের একটি স্থিতিশীল লোকাল ID আছে প্লাস সার্ভার ID যখন উপলব্ধ।
  • স্পষ্ট স্টেট আছে (queued, syncing, sent, failed, needs review) এবং কনসিস্টেন্টভাবে ব্যবহৃত হচ্ছে।
  • রিকোয়েস্টগুলো আইডেম্পোটেন্ট (রিট্রাই নিরাপদ), এবং প্রতিটি অপারেশনে একটি idempotency key আছে।
  • রেকর্ডগুলোর ভার্সনিং আছে (updatedAt, revision number, অথবা ETag) যাতে সংঘাত ধরা যায়।
  • সংঘাত নিয়মগুলি সাধারণ ভাষায় লেখা আছে (কি জিতবে, কি মিশবে, কখন ব্যবহারকারীকে জিজ্ঞেস করা হবে)।

এগুলো স্থাপন করার পরে, অভিজ্ঞতাটি ডেটা মডেলের মতই শক্ত কিনা যাচাই করুন। ব্যবহারকারীরা দেখতে পারা উচিত কী pending আছে, কী ব্যর্থ হয়েছে, এবং কার্যকরভাবে কাজ নিতে পারে যা কাজ হারানোর ভয় ছাড়াই।

বাস্তব জীবনের সাথে মেলে এমন সিনারিও দিয়ে টেস্ট করুন:

  • প্লেন মোড এডিট: তৈরি, আপডেট, ডিলিট, তারপর পুনরায় কানেক্ট করুন।
  • অনিশ্চিত নেটওয়ার্ক: সিঙ্ক মাঝে মধ্যে ছিন্ন করুন এবং নিশ্চিত করুন রিট্রাই ডুপলিকেট তৈরি করেনা।
  • অ্যাপ কিল করা: সেন্ড করার সময় জোরপূর্বক ক্লোজ করুন, আবার খুলে নিশ্চিত করুন কিউ পুনরুদ্ধার হয়।
  • ক্লক স্কিউ: ডিভাইস টাইম ভুল থাকলে সংঘাত শনাক্তকরণ কাজ করে কিনা দেখুন।
  • ডুপল ট্যাপ: ব্যবহারকারী Save দুইবার চাপলে তা একটি সার্ভার পরিবর্তনে পরিণত হয় কিনা নিশ্চিত করুন।

UI পালিশ করার আগে পুরো ফ্লো প্রোটোটাইপ করুন। এক স্ক্রীন, এক রেকর্ড টাইপ, এবং এক সংঘাত কেস (একই ফিল্ডে দুজনের এডিট) দিয়ে শুরু করুন। একটি সহজ সিঙ্ক স্ট্যাটাস এলাকা, ব্যর্থতার জন্য একটি Retry বটন, এবং একটি স্পষ্ট সংঘাত স্ক্রীন রাখুন। যখন তা কাজ করবে, সেটি অন্যান্য স্ক্রিনে পুনরাবৃত্তি করুন।

আপনি যদি কোড ছাড়া বানান, AppMaster (appmaster.io) নেটিভ Kotlin ও SwiftUI আউটপুটসহ ব্যাকএন্ড জেনারেট করতে পারে, যাতে আপনি কিউ, ভার্সন চেক এবং ব্যবহারকারী-মুখী স্টেটগুলোর দিকে মনোযোগ রাখতে পারেন হাতের লেগে সব কিছু ওয়্যারিং না করে।

শুরু করা সহজ
কিছু আশ্চর্যজনকতৈরি করুন

বিনামূল্যের পরিকল্পনা সহ অ্যাপমাস্টারের সাথে পরীক্ষা করুন।
আপনি যখন প্রস্তুত হবেন তখন আপনি সঠিক সদস্যতা বেছে নিতে পারেন৷

এবার শুরু করা যাক