فصل یازدهم: گسترش اپلیکیشن

در این فصل، به گسترش اپلیکیشن مرکز اجاره کشتی‌های کروز با افزودن ویژگی‌های پیشرفته می‌پردازیم. این ویژگی‌ها شامل احراز هویت با استفاده از @sidebase/nuxt-auth، اتصال به پایگاه داده با Supabase یا Prisma، پرداخت آنلاین با Stripe، و تحلیل داده‌ها با @nuxtjs/plausible است. این قابلیت‌ها اپلیکیشن را به یک محصول کامل و آماده برای استفاده تجاری تبدیل می‌کنند. هر بخش به‌طور کامل توضیح داده شده و مراحل پیاده‌سازی شرح داده می‌شوند.


احراز هویت (Authentication)

برای افزودن احراز هویت به اپلیکیشن، از ماژول @sidebase/nuxt-auth استفاده می‌کنیم که یک راه‌حل مدرن و ساده برای پیاده‌سازی OAuth یا JWT در Nuxt 3 ارائه می‌دهد.

مراحل پیاده‌سازی:

  1. نصب ماژول:
   npm install @sidebase/nuxt-auth
  1. به‌روزرسانی nuxt.config.ts:
   export default defineNuxtConfig({
     modules: ['@pinia/nuxt', '@nuxtjs/tailwindcss', '@nuxt/image', '@nuxt/content', '@sidebase/nuxt-auth'],
     auth: {
       provider: {
         type: 'authjs',
         trustHost: true,
         defaultProvider: 'github', // یا Google، Auth0 و غیره
       },
     },
   });
  1. ایجاد فایل تنظیمات Auth.js:

  2. فایل server/api/auth/[...].ts را برای مدیریت مسیرهای احراز هویت ایجاد کنید:

     // server/api/auth/[...].ts
     import { NuxtAuthHandler } from '#auth';
     import GithubProvider from 'next-auth/providers/github';

     export default NuxtAuthHandler({
       providers: [
         GithubProvider({
           clientId: process.env.GITHUB_CLIENT_ID,
           clientSecret: process.env.GITHUB_CLIENT_SECRET,
         }),
       ],
     });
  1. تنظیم متغیرهای محیطی:

  2. در فایل .env، کلیدهای OAuth را اضافه کنید:

     GITHUB_CLIENT_ID=your-github-client-id
     GITHUB_CLIENT_SECRET=your-github-client-secret
  1. به‌روزرسانی میدلور:

  2. میدلور احراز هویت (middleware/auth.ts) را برای استفاده از @sidebase/nuxt-auth به‌روزرسانی کنید:

     // middleware/auth.ts
     import { useAuth } from '#auth';

     export default defineNuxtRouteMiddleware(async (to) => {
       const { status } = useAuth();
       if (to.path === '/bookings' && status.value !== 'authenticated') {
         return navigateTo('/login');
       }
     });
  1. ایجاد صفحه ورود:

  2. فایل pages/login.vue را برای ورود کاربران ایجاد کنید:

     <!-- pages/login.vue -->
     <template>
       <div class="container mx-auto p-6">
         <h1 class="text-3xl font-bold mb-6">Login</h1>
         <button @click="signInWithGithub" class="btn">Sign in with GitHub</button>
       </div>
     </template>

     <script setup>
     import { signIn } from '#auth';

     const signInWithGithub = async () => {
       await signIn('github', { callbackUrl: '/bookings' });
     };
     </script>

توضیحات:

  • ماژول @sidebase/nuxt-auth: از Auth.js (NextAuth) برای مدیریت احراز هویت استفاده می‌کند و با Nuxt 3 ادغام شده است.
  • ارائه‌دهنده‌ها: در این مثال، از GitHub به‌عنوان ارائه‌دهنده OAuth استفاده شده است، اما می‌توان از Google، Auth0 یا JWT استفاده کرد.
  • میدلور: بررسی می‌کند که آیا کاربر احراز هویت شده است یا خیر و در صورت لزوم به صفحه ورود هدایت می‌کند.
  • کاربرد: این سیستم احراز هویت دسترسی به صفحه رزروها (/bookings) را محدود می‌کند و تجربه کاربری ایمن‌تری فراهم می‌کند.
  • مزایا:

  • پشتیبانی از چندین ارائه‌دهنده OAuth.

  • ادغام ساده با Nuxt 3 و موتور Nitro.
  • مدیریت خودکار سشن‌ها و توکن‌ها.

اتصال به پایگاه داده (Database)

برای ذخیره‌سازی دائمی داده‌ها (مانند کشتی‌ها و رزروها)، می‌توان از Supabase (پایگاه داده ابری مبتنی بر PostgreSQL) یا Prisma (ORM برای پایگاه داده‌های مختلف) استفاده کرد.

گزینه ۱: ادغام با Supabase

  1. نصب ماژول:
   npm install @nuxtjs/supabase
  1. به‌روزرسانی nuxt.config.ts:
   export default defineNuxtConfig({
     modules: ['@pinia/nuxt', '@nuxtjs/tailwindcss', '@nuxt/image', '@nuxt/content', '@sidebase/nuxt-auth', '@nuxtjs/supabase'],
     supabase: {
       url: process.env.SUPABASE_URL,
       key: process.env.SUPABASE_KEY,
     },
   });
  1. تنظیم متغیرهای محیطی:
   SUPABASE_URL=your-supabase-url
   SUPABASE_KEY=your-supabase-key
  1. به‌روزرسانی مسیرهای سرور:

  2. مسیر /api/ships را برای دریافت داده‌ها از Supabase به‌روزرسانی کنید:

     // server/api/ships.ts
     import { serverSupabaseClient } from '#supabase/server';
     import type { Ship } from '~/types';

     export default defineEventHandler(async (event): Promise<Ship[]> => {
       const client = serverSupabaseClient(event);
       const { data } = await client.from('ships').select('*');
       return data || [];
     });
  • مسیر /api/bookings را برای مدیریت رزروها به‌روزرسانی کنید:
     // server/api/bookings.ts
     import { serverSupabaseClient } from '#supabase/server';
     import type { Booking } from '~/types';

     export default defineEventHandler({
       async get(event) {
         const client = serverSupabaseClient(event);
         const { data } = await client.from('bookings').select('*');
         return data || [];
       },
       async post(event) {
         const client = serverSupabaseClient(event);
         const body = await readBody(event);
         const newBooking: Booking = {
           id: Date.now(), // در تولید از UUID استفاده کنید
           shipId: body.shipId,
           startDate: new Date(body.startDate),
           endDate: new Date(body.endDate),
           totalPrice: body.totalPrice,
         };
         const { data } = await client.from('bookings').insert(newBooking).select();
         return data[0];
       },
     });
  1. ایجاد جداول در Supabase:

  2. در داشبورد Supabase، دو جدول ایجاد کنید:

    • جدول ships: با ستون‌های id, name, capacity, pricePerDay, amenities, image.
    • جدول bookings: با ستون‌های id, shipId, startDate, endDate, totalPrice.

گزینه ۲: ادغام با Prisma

  1. نصب Prisma:
   npm install prisma @prisma/client
   npx prisma init
  1. تنظیم فایل prisma/schema.prisma:
   datasource db {
     provider = "postgresql"
     url      = env("DATABASE_URL")
   }

   model Ship {
     id          Int      @id @default(autoincrement())
     name        String
     capacity    Int
     pricePerDay Int
     amenities   String[]
     image       String
     bookings    Booking[]
   }

   model Booking {
     id         Int      @id @default(autoincrement())
     shipId     Int
     startDate  DateTime
     endDate    DateTime
     totalPrice Int
     ship       Ship     @relation(fields: [shipId], references: [id])
   }
  1. به‌روزرسانی مسیرهای سرور:

  2. مشابه Supabase، مسیرهای /api/ships و /api/bookings را برای استفاده از Prisma به‌روزرسانی کنید:

     // server/api/ships.ts
     import { PrismaClient } from '@prisma/client';
     import type { Ship } from '~/types';

     const prisma = new PrismaClient();

     export default defineEventHandler(async (): Promise<Ship[]> => {
       return prisma.ship.findMany();
     });

توضیحات:

  • Supabase: یک پایگاه داده ابری با API ساده و ادغام مستقیم با Nuxt از طریق @nuxtjs/supabase. مناسب برای پروژه‌های کوچک تا متوسط.
  • Prisma: یک ORM قدرتمند که با پایگاه داده‌های مختلف (مانند PostgreSQL، MySQL) کار می‌کند و برای پروژه‌های پیچیده‌تر مناسب است.
  • کاربرد: این ادغام‌ها جایگزین ذخیره‌سازی موقت در حافظه (مانند آرایه bookings در فصل ششم) می‌شوند و داده‌ها را به‌صورت دائمی ذخیره می‌کنند.
  • مزایا:

  • مقیاس‌پذیری و پایداری داده‌ها.

  • پشتیبانی از پرس‌وجوهای پیچیده.
  • ادغام آسان با Nuxt.

پرداخت آنلاین (Payments)

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

مراحل پیاده‌سازی:

  1. نصب Stripe:
   npm install @stripe/stripe-js stripe
  1. ایجاد مسیر سرور برای پرداخت:

  2. فایل server/api/stripe-checkout.ts را ایجاد کنید:

     // server/api/stripe-checkout.ts
     import Stripe from 'stripe';
     import type { Booking } from '~/types';

     const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, { apiVersion: '2024-06-20' });

     export default defineEventHandler(async (event) => {
       const body = await readBody(event);
       const booking: Booking = body.booking;

       const session = await stripe.checkout.sessions.create({
         payment_method_types: ['card'],
         line_items: [
           {
             price_data: {
               currency: 'usd',
               product_data: { name: `Booking for Ship ${booking.shipId}` },
               unit_amount: booking.totalPrice * 100, // Stripe از سنت استفاده می‌کند
             },
             quantity: 1,
           },
         ],
         mode: 'payment',
         success_url: `${useRuntimeConfig().public.appUrl}/bookings?success=true`,
         cancel_url: `${useRuntimeConfig().public.appUrl}/bookings?canceled=true`,
       });

       return { id: session.id };
     });
  1. به‌روزرسانی nuxt.config.ts:
   export default defineNuxtConfig({
     runtimeConfig: {
       public: {
         appUrl: process.env.APP_URL || 'http://localhost:3000',
         stripePublishableKey: process.env.STRIPE_PUBLISHABLE_KEY,
       },
       stripeSecretKey: process.env.STRIPE_SECRET_KEY,
     },
   });
  1. به‌روزرسانی فرم رزرو در pages/ships/[id].vue:
   <script setup>
   import { loadStripe } from '@stripe/stripe-js';

   const submit = handleSubmit(async (values) => {
     if (!ship.value) return;
     const days = (new Date(values.endDate) - new Date(values.startDate)) / (1000 * 60 * 60 * 24);
     const totalPrice = days * ship.value.pricePerDay;
     const booking = {
       shipId: ship.value.id,
       startDate: new Date(values.startDate),
       endDate: new Date(values.endDate),
       totalPrice,
     };

     const { id } = await $fetch('/api/stripe-checkout', {
       method: 'POST',
       body: { booking },
     });

     const stripe = await loadStripe(useRuntimeConfig().public.stripePublishableKey);
     await stripe.redirectToCheckout({ sessionId: id });

     await bookingsStore.addBooking(booking);
     alert('Booking successful!');
     form.startDate = '';
     form.endDate = '';
   });
   </script>
  1. تنظیم متغیرهای محیطی:
   STRIPE_PUBLISHABLE_KEY=your-stripe-publishable-key
   STRIPE_SECRET_KEY=your-stripe-secret-key
   APP_URL=https://your-app-url.com

توضیحات:

  • Stripe: امکان پردازش پرداخت‌های آنلاین را فراهم می‌کند.
  • مسیر سرور: یک جلسه پرداخت (Checkout Session) در Stripe ایجاد می‌کند و کاربران را به صفحه پرداخت هدایت می‌کند.
  • فرم رزرو: پس از اعتبارسنجی فرم، یک درخواست به مسیر Stripe ارسال می‌شود و کاربر به صفحه پرداخت Stripe هدایت می‌شود.
  • مزایا:

  • امنیت بالا با استانداردهای PCI.

  • پشتیبانی از پرداخت‌های بین‌المللی.
  • تجربه کاربری ساده با ریدایرکت به صفحه پرداخت.

تحلیل داده‌ها (Analytics)

برای ردیابی رفتار کاربران و تحلیل عملکرد اپلیکیشن، از Plausible Analytics با ماژول @nuxtjs/plausible استفاده می‌کنیم.

مراحل پیاده‌سازی:

  1. نصب ماژول:
   npm install @nuxtjs/plausible
  1. به‌روزرسانی nuxt.config.ts:
   export default defineNuxtConfig({
     modules: ['@pinia/nuxt', '@nuxtjs/tailwindcss', '@nuxt/image', '@nuxt/content', '@sidebase/nuxt-auth', '@nuxtjs/supabase', '@nuxtjs/plausible'],
     plausible: {
       domain: 'your-app-url.com',
       apiHost: 'https://plausible.io', // یا سرور خودهاست‌شده
     },
   });
  1. تنظیم متغیرهای محیطی:

  2. اگر از Plausible خودهاست‌شده استفاده می‌کنید، متغیر PLAUSIBLE_API_HOST را در .env اضافه کنید:

     PLAUSIBLE_API_HOST=https://your-plausible-host.com
  1. ردیابی رویدادهای سفارشی:

  2. برای ردیابی رزروهای موفق، در pages/ships/[id].vue یک رویداد به Plausible ارسال کنید:

     import { usePlausible } from '#plausible';

     const plausible = usePlausible();
     const submit = handleSubmit(async (values) => {
       // ... کد پرداخت و رزرو
       plausible('Booking Completed', { props: { shipId: ship.value.id, totalPrice } });
     });

توضیحات:

  • Plausible Analytics: یک ابزار تحلیل سبک و متمرکز بر حریم خصوصی که جایگزین Google Analytics است.
  • ماژول @nuxtjs/plausible: ردیابی خودکار بازدیدهای صفحه و رویدادهای سفارشی را فراهم می‌کند.
  • کاربرد: ردیابی رزروها، بازدید صفحات، یا اقدامات کاربر (مانند کلیک روی دکمه‌ها).
  • مزایا:

  • سبک و بدون کوکی، مناسب برای قوانین حریم خصوصی (مانند GDPR).

  • ادغام ساده با Nuxt.
  • امکان ردیابی رویدادهای سفارشی.

جمع‌بندی فصل یازدهم

در این فصل، اپلیکیشن مرکز اجاره کشتی‌های کروز را با افزودن ویژگی‌های پیشرفته گسترش دادیم:

  • احراز هویت: با @sidebase/nuxt-auth برای محدود کردن دسترسی به صفحات حساس.
  • پایگاه داده: با Supabase یا Prisma برای ذخیره‌سازی دائمی داده‌ها.
  • پرداخت آنلاین: با Stripe برای پردازش پرداخت رزروها.
  • تحلیل داده‌ها: با @nuxtjs/plausible برای ردیابی رفتار کاربران.

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