
همه چیز از یک مسئله به ظاهر ساده شروع شد. تیم مارکتینگ اپلیکیشن بله کمپین جدیدی برای تبلیغ سرویس ارز اربعین آماده کرده بود و متنها نوشته شده، تصاویر آماده و برنامه زمانبندی مشخص بود.
تنها یک کار باقی مانده بود: اضافه کردن کامپوننتها و محتوا به لندینگ.
ولی این مسئله تنها یک بار نبود و بارها این مکالمه بین همکاران محتوا و توسعهدهنده تکرار میشد:
«میتونی این یک خط متن رو در لندینگ ارز تغییر بدی؟»
«میتونی این عکس رو با یک عکس جدید جایگزین کنی؟»
«میتونی این پرسش رو به بخش FAQ اضافه کنی؟»
و در ذهن ما برنامهنویسها، جمله «فقط یه متن سادهست» همیشه یعنی آغاز یک چرخه طولانی: پیدا کردن فایلها، تغییر کد، کامیت، پوش به گیت، منتظر ماندن برای بیلد، دیپلوی… و این وسط همه کارهای دیگر در صف توسعه عقب میافتاد.
این صحنه بارها تکرار میشد؛ کمپین تبلیغات، معرفی سرویس ارز، تغییر قیمتها، اصلاح یک دکمه… تغییراتی که برای تیمهای غیر فنی ساده و پیشپاافتاده بودند، اما برای توسعهدهندگان یعنی ورود به کد، صرف زمان و از دست دادن تمرکز وسط کارهای پیچیدهتر. این مسئله مستقیما در زمان انتشار کمپینها و سرعت اجرای آنها موثر بود.
وقتی بحث «تغییر محتوای لندینگها و ساخت لندینگ جدید» دوباره مطرح شد، از خودمان پرسیدیم:
«چرا تیمهای محتوا و محصول نمیتوانند خودشان این تغییرات را انجام دهند؟»
که پاسخ آن ساده بود: ابزار لازم را نداشتند و تغییر مستقیم کد برایشان سخت و پرریسک بود.
CMSهای آماده مثل WordPress یا Strapi هرچند قدرتمند هستند، اما برای ما دو مشکل داشتند:
قالبهای آنها اجازه تغییرات آزادانه در طراحی را میدهند که این یعنی از دست رفتن انسجام دیزاین سیستم لندینگهای بله.
اتصالشان به فرآیند کاری ما در GitLab و پایپلاینهای خودکار، یکپارچه و بدون دردسر نبود و تاریخچه تغییرات محتوا همیشه در دسترس نبود.
بنابراین، پس از بررسی ابزارهای در دسترس انتخاب ما در بله TinaCMS شد، یک سیستم ویرایش درونصفحهای که اجازه میدهد همانجا که محتوا را میبینیم، آن را تغییر دهیم.
با توجه به اینکه لندینگهای بله با فریمورک Next.js ساخته شده بودند، این CMS را روی پروژهها اضافه کردیم.
به کمک چپتر طراحی، دیزاین سیستم لندینگهای بله در قالب کامپوننتهای مختلف با فیلدهای کنترلی مشخص در TinaCMS پیادهسازی شد.
یکی از مزایای TinaCMS این است که میتوان آن را مستقیماً به سیستم کنترل ورژن (GitHub، GitLab و …) متصل کرد، تا هر تغییر محتوایی روی فایل Markdown مربوط به آن لندینگ ثبت و خودکار پوش شود.
از خاصیت route محور بودن Next.js برای ساخت لندینگهای جدید استفاده کردیم و قابلیت ساخت لندینگ جدید هم با تعریف یک لندینگ جدید در cms و ایجاد یک Markdown جدید به صورت خودکار در route مورد نظر ایجاد شد.
فرآیند تغییر محتوا یا ساخت لندینگ جدید حالا اینطور پیش میرود:
تیم محتوا یا طراح محصول تغییرات را در TinaCMS اعمال میکند.
تغییرات بهطور خودکار به ریپازیتوری GitLab بله پوش میشود و یک Merge Request ساخته میشود.
توسعهدهنده فرانتاند تغییرات را بررسی کرده و در صورت تأیید Merge میکند.
سیستم CI/CD Pipeline به صورت خودکار بیلد جدید را ساخته و دیپلوی میکند.

پیش از اینکه دقیقتر علتهای انتخاب TinaCMS را در بله بررسی کنیم، خوبه که مروری بر یک دستهبندی از کلی cmsها انجام بدیم:
Headless CMS: محتوا در یک بکاند ابری یا self-hosted نگهداری میشود و از طریق REST/GraphQL API در دسترس قرار میگیرد. مثالها: Contentful، Sanity، Strapi، Prismic.
File-based CMS: محتوا به صورت فایلهای Markdown/MDX/JSON مستقیماً در ریپازیتوری پروژه قرار دارد؛ ویرایشگران یا مستقیم کامیت میکنند یا از یک ویرایشگر وب استفاده میکنند که فایلها را مینویسد. مثالها: Netlify CMS، Decap CMS، TinaCMS.
هر دو با Next.js به خوبی کار میکنند؛ تفاوتها بیشتر در تجربه توسعهدهنده، مقیاسپذیری و فرآیند ویرایش محتوا و رابطکاربریست.
یکی از مواردی که برای ما اهمیتی داشت ورژن کنترل و ذخیره محتوا در گیتلب بله بود. ما میخواستیم تغییرات محتوا و جابهجایی کامپوننتها و ویرایش آنها را به راحتی در دسترس باشند و بتوانیم تاریخچه آنها را هم داشته باشیم. از این رو CMS های مبتنی بر فایل که TinaCMS یکی از آنها بود انتخاب بهتری بود.
چند ویژگی کلیدی TinaCMS کاملاً با نیازهای ما همخوانی داشت:
اوپن سورس و Self-hosted: ما آن را روی سرورهای بله با تدابیر امنیتی کامل دیپلوی کردیم.
ویرایش بصری در لحظه: هر تغییر فوراً در لندینگ قابل مشاهده است و هم از لحاظ محتوایی و هم بصری میتوان تغییرات را اعمال و پیش از انتشار بررسی کرد.
بلاکمحور و کامپوننتهای سفارشی: بدون محدودیت در ساختار یا طراحی؛ طراحان کامپوننتها را مطابق دیزاین سیستم طراحی میکنند، توسعهدهندگان پیادهسازی میکنند، و در CMS مانند اجزای آماده در اختیار کاربران قرار میگیرد.
API ساده: انتقال لندینگهای قبلی به CMS جدید آسان و سریع انجام شد.
تغییرات کامپوننتها و فیلدها به راحتی انجام میشود. به عنوان مثال یک فیلد مشابه زیر تعریف میشود:
const ImageText: Template = { name: "imageText", label: "متن و تصویر", type: "object", ui: { itemProps: (item) => { return { label: "متن و تصویر- " + item?.text }; }, }, fields: [ { name: "text", label: "متن", type: "string", }, { name: "image", label: "تصویر", type: "image", }, ], };
با پیشرفت مدلهای هوش مصنوعی هم در زمینه برنامه نویسی و هم در زمینه طراحی بخش زیادی از این فرآیند میتواند توسط هوش مصنوعی انجام شود. مثلا اگر تیمی نیازمندیای برای پیادهسازی کامپوننتی در لندینگها دارد میتواند با استفاده از ابزارهایی مثل Figma make یا سایر ابزارهای طراحی با ai آن را پیادهسازی کند و برنامهنویسها هم با استفاده از Figma connect و ابزارهایی مثل claude code، cursor یا نمونه مشابه آنها کامپوننتها را پیاده کنند و بیش از چندین برابر در زمان توسعه صرفه جویی کنند.
با توجه به پیشرفت ابزارها و هوشمصنوعی هم در زمان توسعه خیلی سریعتر کامپوننتها به cms اضافه میشوند و هم در صورت آماده بودن محتوا تنها در دو ساعت میتوان یک لندینگ جدید و کامل به لندینگهای بله اضافه کرد و آن را منتشر کرد، فرآیندی که قبلا شاید چند روز زمان میبرد تا در دسترس کاربران قرار بگیرد.
حالا تیمهای محتوا و محصول میتوانند خیلی سریع تغییر ایجاد کنند، آن را تست کنند و تا رسیدن به نتیجه دلخواه اصلاحات را اعمال کنند، بدون انتظار برای برنامهنویسها. وقتی همهچیز آماده شد، فقط به یک توسعهدهنده خبر میدهند تا Merge و Deploy انجام شود. این یه تاثیر خیلی مثبت در کاهش زمان توسعه و انتشار لندینگها و ذخیره زمان توسعهدهندگان داشته است.