• کارنامه

تجربه‌هایی که پشت ویترین مانده‌اند

کارنامه‌ام فقط سایت‌های روی ویترین نیست. بیشتر کارها روی محصول زنده بوده؛ فروشگاه، اپ، ابزار داخلی، گمرک، سرور و وردپرس. اینجا همان تجربه‌ها را به زبان مسئله نوشته‌ام، نه لیست تکنولوژی.

01

فروشگاه و پرداخت

خیلی فروشگاه‌ها ظاهر قشنگی دارند، ولی پرداخت که می‌رسد می‌شکنند. قسط جداست، درگاه جدا، سفارش جدا. من روی همین نقطه کار کرده‌ام؛ جایی که اشتباه یعنی تماس پشتیبانی، نه باگ روی کاغذ.

  • WooCommerce
  • Installments
  • Crypto

پرداخت قسطی روی فروشگاه زنده

برای همهمشتری می‌خواست خرید قسطی باشد، بدون اینکه فروشگاه از ووکامرس جدا شود. قسط باید داخل همان سبد و سفارش دیده شود، نه یک فرم جدا که بعداً دستی چک شود.

برای متخصصپلاگین سفارشی اقساط روی WooCommerce، اتصال به order lifecycle و وضعیت سفارش، به‌جای فرم ایزوله.

درگاه خارج از مسیر معمولی

برای همهبرای فروش با محدودیت درگاه ریالی، مسیر پرداخت کریپتو را کنار checkout ساختم تا سفارش همان‌جا ثبت شود، نه در اکسل بعد از فیش.

برای متخصصcrypto payment موازی با checkout، با ثبت سفارش و وضعیت پرداخت مشخص.

نمونه کد

php
add_action('woocommerce_checkout_order_processed', function ($order_id) {
    $order = wc_get_order($order_id);
    $plan = sanitize_text_field($_POST['installment_plan'] ?? '');

    if (!$order || $plan === '') {
        return;
    }

    $order->update_meta_data('_installment_plan', $plan);
    $order->update_status('on-hold', 'Waiting for installment confirmation');
    $order->save();
});
02

اپ و تجربه موبایل

بعضی کارها روی دسکتاپ تمام می‌شوند. بعضی‌ها باید در جیب باشند: فروشگاه، پورتال، یا محصولی که کاربر هر روز باز می‌کند. من هم اپ نیتیو ساخته‌ام، هم وب‌ویو کنترل‌شده، هم رابطی که روی موبایل مثل اپ حس شود.

  • React Native
  • WebView
  • PWA

اپ فروشگاه روی React Native

برای همهبرای فروشگاهی که مشتری‌اش بیشتر با موبایل می‌آمد، به‌جای فقط نسخه واکنش‌گرا، رابط فروش را به اپ بردم تا سبد و محصول زیر انگشت باشد.

برای متخصصReact Native برای UI فروشگاه، اتصال به API موجود، بدون بازنویسی کل بک‌اند.

سایت داخل اپ، با مرز مشخص

برای همهبعضی محصول‌ها باید همان سایت زنده را نشان بدهند، اما داخل اپ. وب‌ویو را طوری بستم که کاربر از مسیر امن خارج نشود و حس اپ حفظ شود.

برای متخصصWebView با محدودیت URL، لودینگ مشخص، و بدون باز شدن پنجرهٔ خارج از کنترل.

نمونه کد

tsx
function ShopWebView({ uri }: { uri: string }) {
  return (
    <WebView
      source={{ uri }}
      startInLoadingState
      setSupportMultipleWindows={false}
      onShouldStartLoadWithRequest={(request) =>
        request.url.startsWith("https://")
      }
    />
  );
}
03

ابزار داخلی شرکت

سایت مشتری ویترین است. پشت آن ابزارهایی است که اگر خراب شوند، کل تیم می‌ایستد: گزارش کار، دسترسی ریموت، داشبورد وضعیت. این‌ها معمولاً پرایوت می‌مانند، ولی بخش بزرگی از کار واقعی همین‌جاست.

  • Dashboard
  • RMM
  • Internal tools

گزارش روزانه به‌جای پیام پراکنده

برای همهبه‌جای اینکه کار روز در چت گم شود، مسیر ثبت گزارش را طوری چیدم که انجام‌شده و مانع‌ها در یک جا جمع شوند و بعداً قابل پیگیری باشند.

برای متخصصمدل داده مشخص برای report، API ثبت، و UI داخلی بدون وابستگی به پیام‌رسان.

داشبورد و ریموت برای تیم فنی

برای همهبرای کارهایی که باید از راه دور دیده و جمع شوند، داشبورد و ابزار ریموت ساختم تا وضعیت سیستم‌ها در یک نگاه باشد، نه در ده تا ریموت جدا.

برای متخصصپنل داخلی، RMM و مانیتورینگ وضعیت؛ جدا از سایت عمومی مشتری.

نمونه کد

ts
type DailyReport = {
  userId: string;
  date: string;
  done: string[];
  blocked: string[];
};

export async function submitReport(report: DailyReport) {
  const response = await fetch("/api/reports", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(report),
  });

  if (!response.ok) {
    throw new Error("Report was not saved");
  }

  return response.json();
}
04

واردات، صادرات و گمرک

داده گمرک و تجارت خارجی اگر خام روی صفحه بیاید، کسی از آن استفاده نمی‌کند. کار این بوده که نقشه، شرکت خارجی، مشاوره و پورتال را به زبانی نشان بدهم که بازرگان بفهمد، نه فقط برنامه‌نویس.

  • React
  • Maps
  • ixport

نقشه گمرک‌های ایران

برای همهبه‌جای جدول طولانی، گمرک‌ها را روی نقشه گذاشتم تا موقعیت و اطلاعات در یک نگاه پیدا شود.

برای متخصصReact + نقشه، مارکر و پاپ‌آپ روی دادهٔ مکانی گمرک.

پورتال صادرات برای کاربر واقعی

برای همهپورتال صادرات باید چندزبانه باشد و مسیر ثبت و پیگیری را برای کسی که برنامه‌نویس نیست روشن کند. همین را در ixport و نسخه‌های مرتبطش جلو بردم.

برای متخصصپورتال چندزبانه، تم child، و لایه داده برای شرکت‌ها و مسیرهای صادرات.

نمونه کد

tsx
const customs = [
  { id: "bandar-abbas", lat: 27.1832, lng: 56.2666, name: "Bandar Abbas" },
  { id: "bushehr", lat: 28.9234, lng: 50.8203, name: "Bushehr" },
];

export function CustomsMap() {
  return customs.map((item) => (
    <Marker key={item.id} position={[item.lat, item.lng]}>
      <Popup>{item.name}</Popup>
    </Marker>
  ));
}
05

زیرساخت و امنیت

دیپلوی یعنی سایت باز شود، ولی کار واقعی بعد از آن است: هدرهای امنیتی، کش استاتیک، کانفیگ nginx، و پنلی که وضعیت را نشان بدهد. این لایه را جدا از ظاهر سایت نگه می‌دارم.

  • Nginx
  • Linux
  • Security

کانفیگ سرور برای سایت زنده

برای همهبرای سایتی که باید سریع و پایدار بماند، مسیر استاتیک را کش کردم و هدرهایی گذاشتم که جلوی اشتباه‌های رایج مرورگر و iframe را بگیرد.

برای متخصصnginx با try_files، کش استاتیک، SSL/HTTP2 و هدرهای امنیتی.

لایه دیده شدن، نه فقط بالا بودن

برای همهبالا بودن سرور کافی نیست. داشبورد و پلتفرم امنیتی را طوری چیدم که وضعیت دیده شود، قبل از اینکه کاربر نهایی با خطا روبه‌رو شود.

برای متخصصپلتفرم مانیتورینگ/امنیت جدا از فرانت عمومی؛ لاگ و وضعیت در پنل داخلی.

نمونه کد

nginx
server {
    listen 443 ssl http2;
    server_name example.com;

    location / {
        try_files $uri $uri/ /index.php?$args;
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Content-Type-Options "nosniff" always;
    }

    location ~* \.(js|css|webp|png)$ {
        expires 30d;
        access_log off;
    }
}
06

وردپرس و پلاگین

بیشتر سایت‌های زنده همین‌جا تمام می‌شوند: تم child روی وودمارت یا هلوی المنتور، پلاگین اقساط، استوری، اسلایدر، پیامک، سبد خرید. وردپرس برای من CMS آماده نیست؛ بستری است که باید مثل محصول رفتار کند.

  • WordPress
  • Plugin
  • Elementor

تم child به‌جای دستکاری قالب اصلی

برای همهظاهر و رفتار سایت را در child theme نگه داشتم تا به‌روزرسانی قالب والد، کار سفارشی را خراب نکند.

برای متخصصchild theme روی Woodmart / Hello / Elementor، override قالب و استایل بدون fork قالب والد.

پلاگین برای کاری که قالب نباید انجام دهد

برای همهاستوری، اسلایدر، ورود پیامکی و سبد سفارشی را به پلاگین بردم تا با عوض شدن ظاهر سایت، منطق از بین نرود.

برای متخصصcustom post type، shortcode، REST، و هوک وردپرس برای قابلیت‌هایی که باید مستقل از تم بمانند.

نمونه کد

php
add_action('init', function () {
    register_post_type('story', [
        'label' => 'Stories',
        'public' => true,
        'show_in_rest' => true,
        'supports' => ['title', 'editor', 'thumbnail'],
    ]);
});

add_shortcode('story_flow', function () {
    $query = new WP_Query([
        'post_type' => 'story',
        'posts_per_page' => 6,
    ]);

    ob_start();
    while ($query->have_posts()) {
        $query->the_post();
        echo '<article>' . esc_html(get_the_title()) . '</article>';
    }
    wp_reset_postdata();
    return ob_get_clean();
});