مدیریت فضای کاری
صورتحساب و پلنها
صورتحساب از طریق Stripe و با استفاده از لاراول کشیر انجام میشود. هر فضای کاری در هر زمان روی یک پلن قرار دارد. این صفحه توضیح میدهد که چه پلنهایی وجود دارند، مصرف چگونه محاسبه میشود و وقتی به محدودیت برسید چه اتفاقی میافتد.
پلنها
پلنها توسط مدیران پلتفرم مدیریت میشوند (مشاهده کنید پلنها و همگامسازی با Stripe) و مشتریان در /app/billing آنها را مشاهده میکنند. هر پلن شامل موارد زیر است:
| فیلد | کاربرد |
|---|---|
name | نام نمایشی (رایگان، حرفهای، سازمانی). |
slug | شناسه ثابت — پس از ایجاد هرگز تغییر نمیکند، حتی اگر نام تغییر کند. |
monthly_conversations | سهمیه مکالمات جدید در هر ماه میلادی. 0 یعنی نامحدود. |
monthly_messages | اختیاری. سهمیه پیامها که در هر نوبت بازدیدکننده در این ماه میلادی محاسبه میشود. برای بدون محدودیت اضافی خالی بگذارید؛ فقط تعداد مکالمات فضای کاری را محدود میکند. |
max_tokens_per_response | اختیاری. max_tokens هوش مصنوعی را برای هر پاسخ در این پلن محدود میکند. برای استفاده از مقدار پیشفرض ۸۰۰ خالی بگذارید. برای کوتاه نگه داشتن پاسخها در نسخه رایگان و مفصل بودن در نسخههای پولی مفید است. |
price_cents | قیمت پلن به سنت (یک بار در هر interval شارژ میشود). 0 یعنی رایگان / سفارشی (همگامسازی با درگاه را رد میکند). |
interval | دوره صورتحساب — month یا year. پیشفرض month است. قیمتهای Stripe، billing_cycles پیپال و دورههای رزورپی همگی از این ستون استخراج میشوند. |
features.remove_branding | فوتر "قدرت گرفته از" را در ویجت مخفی میکند. |
نسخههای ماهانه و سالانه
برای ارائه تخفیف سالانه، همان پلن را دو بار ایجاد کنید — یکی با interval=month و دیگری با interval=year — و قیمت سالانه را زیر ۱۲ برابر ماهانه قرار دهید. صفحه قیمتگذاری بازاریابی هر دو نوع را تشخیص داده و یک کلید ماهانه/سالانه نمایش میدهد. هر درگاه به دوره بومی خود همگامسازی میشود:
- Stripe —
recurring.interval = month|yearروی قیمت. - PayPal —
billing_cycles[].frequency.interval_unit = MONTH|YEAR. - Razorpay —
period = monthly|yearlyروی پلن.
فضاهای کاری همچنان در هر زمان روی یک ردیف پلن اشتراک دارند (یک workspaces.plan_id) و تغییر از ماهانه به سالانه یک تغییر پلن معمولی است — درگاه یا بهصورت نسبتی محاسبه میکند (Stripe / PayPal) یا چرخه جدید را در مرز صورتحساب بعدی بسته به تنظیمات فضای کاری شروع میکند.
محدودیتهای نرخ هوش مصنوعی
دو کلید محدودیت اختیاری (monthly_messages و max_tokens_per_response) در بخش "محدودیتهای نرخ هوش مصنوعی" در فرم پلن قرار دارند. آنها در زمان اجرا اعمال میشوند:
-
هر پیام بازدیدکننده یک ردیف
messageدرusage_eventsثبت میکند.MeteredBilling::canSendMessage()آنها را برای ماه میلادی جاری جمع کرده و زمانی که مجموع بهmonthly_messagesبرسد، جریان SSE را با یک رویداد خطایmessage_quota_exceededمتوقف میکند. -
MessageStreamControllermaxTokensFor()را در هر نوبت یک بار میخواند (ارزان — یک ردیف از پلن فضای کاری، در درخواستی که کنترلرنده در حال بارگذاری آن است) و آن را از طریق حلقه ابزار و فراخوانی نهایی جریان عبور میدهد.
همگامسازی با Stripe
وقتی یک مدیر یک پلن پولی ایجاد یا بهروز میکند، سرویس StripeProductSync تضمین میکند که یک محصول و قیمت Stripe مطابقت وجود داشته باشد. مشتریان هرگز مستقیماً با Stripe سروکار ندارند تا زمان تسویه حساب — آنها یک پلن را در رابط Pitchbar انتخاب کرده و از طریق کشیر به Stripe Checkout هدایت میشوند.
در تغییر قیمت، قیمت قدیمی Stripe بایگانی شده و یک قیمت جدید ایجاد میشود (قیمتهای Stripe غیرقابل تغییر هستند). اشتراکهای موجود با قیمت قدیمی باقی میمانند؛ اشتراکهای جدید از قیمت جدید استفاده میکنند. این همان رفتار هر SaaS بومی Stripe است.
اشتراک
از /billing، یک عضو فضای کاری با مجوز billing.manage میتواند:
- یک پلن از جدول مقایسه انتخاب کند.
- به Stripe Checkout هدایت شود.
- پرداخت کند؛ Stripe با یک پیام موفقیت به
/billingبازمیگردد. - وبهوک Stripe
plan_idفضای کاری را بهروز کرده و یک ردیفplan_subscriptionایجاد میکند.
کارت ثبتشده از طریق Customer Portal Stripe مدیریت میشود. دکمه مدیریت کارت در /billing آن را باز میکند.
برابری ماتریس عمومی /pricing
جدول مقایسه عمومی /pricing و کارتهای پلن درون برنامهای /billing باید همان ده ردیف قابلیت را نمایش دهند تا مشتریان بالقوه چیزی کمتر از آنچه مشتریان در محصول دریافت میکنند نبینند: دستیاران فروش منتشر شده، مکالمات ماهانه، پیامهای هوش مصنوعی در ماه، اعضای فضای کاری، فضاهای کاری برای هر مالک، منابع دانش، فرآیندهای خودکار، اتصالات، دسترسی API، حذف برند. تست بازگشتی tests/Feature/Marketing/PricingMatrixParityTest در صورت انحراف یک ردیف از ماتریس عمومی، CI را با شکست مواجه میکند.
سهمیهها
پلن رایگان مکالمات جدید ماهانه را محدود میکند. اعمال محدودیت در مسیر اصلی انجام میشود — هر فراخوانی /v1/widget/init از MeteredBilling::canStartConversation() میپرسد که آیا فضای کاری زیر سقف پلن خود است یا نه. اگر نه:
{
"error": {
"code": "plan_limit_reached",
"message": "این فضای کاری به سقف مکالمات ماهانه خود رسیده است. برای ادامه ارتقا دهید."
}
}
با کد ۴۲۹ بازگردانده میشود. بارگذار ویجت وقتی این خطا را ببیند، راهانداز را بهخوبی مخفی میکند — بازدیدکنندگان یک وضعیت خراب نمیبینند.
چه چیزی یک مکالمه محسوب میشود
هر ردیف مکالمه منحصربهفرد بهعنوان ۱ محاسبه میشود، که توسط IncrementUsageJob زمانی که اولین نوبت مکالمه کامل میشود، فعال میشود. مکالمات آزمایشی (is_playground=true) محاسبه نمیشوند، بنابراین مالکان دستیاران فروش میتوانند آزادانه تست کنند.
مکالمات از سر گرفته شده دوباره محاسبه نمیشوند — فقط init اولیه شمارنده را افزایش میدهد.
حذف برند
پلنهایی با features.remove_branding = true فوتر "قدرت گرفته از Pitchbar" را در ویجت مخفی میکنند. پلن رایگان با برند ارائه میشود؛ پلنهای پولی معمولاً بدون برند هستند. مدل Plan این را بهصورت $plan->removesBranding() ارائه میدهد که در زمان init فراخوانی میشود.
فاکتورها
Stripe فاکتورها را به ایمیل صورتحساب ثبتشده ارسال میکند. تاریخچه کامل در Customer Portal Stripe موجود است (مدیریت کارت ← فاکتورها). کشیر همچنین $workspace->invoices() را در سمت سرور ارائه میدهد اگر میخواهید آنها را درون برنامه نمایش دهید.
چرخه حیات: لغو، ازسرگیری، تعویض
کنترلهای رو به مشتری در /app/billing قرار دارند:
- لغو اشتراک. Stripe لغو را در پایان دوره فعلی برنامهریزی میکند (تا آن زمان دسترسی دارید). PayPal بلافاصله لغو میکند (PayPal CANCELLED را یک وضعیت نهایی میداند). Razorpay لغو را در پایان دوره برنامهریزی میکند.
-
ازسرگیری اشتراک. فقط Stripe، و فقط در صورتی که لغو هنوز اعمال نشده باشد (هنوز در
onGracePeriodکشیر). PayPal CANCELLED قابل ازسرگیری نیست؛ دوباره اشتراک میدهید. Razorpay نیز از ازسرگیری اشتراک لغو شده پشتیبانی نمیکند. -
تعویض پلن (ارتقا / کاهش). Stripe یک تعویض درجا با محاسبه نسبتی در فاکتور بعدی انجام میدهد. PayPal و Razorpay تعویض درجای تمیزی ندارند، بنابراین کلیک روی پلن دیگر، اشتراک فعلی را لغو کرده و دوباره وارد تسویه حساب میکند. بخش پاکسازی یتیمهای
CheckoutControllerتضمین میکند که هرگز هر دو اشتراک را همزمان پرداخت نمیکنید.
تطابق پس از تسویه حساب
سرویس SubscriptionReconciler یک شبکه ایمنی برای تحویل وبهوک است. پس از یک تسویه حساب موفق، مشتری به /app/billing?checkout=success هدایت میشود (Stripe همچنین session_id={CHECKOUT_SESSION_ID} را اضافه میکند) و کنترلرنده وضعیت اشتراک زنده را مستقیماً از درگاه دریافت کرده و workspace.plan_id را در همان درخواست تغییر میدهد. صفحه پلن صحیح را حتی زمانی که:
- نقطه پایانی وبهوک Stripe هنوز در داشبورد Stripe مشتری ثبت نشده است (در نصبهای تازه بسیار رایج است).
- وبهوک فعال میشود اما نقطه پایانی ما بهطور موقت از کار افتاده است / امضا مطابقت ندارد / توسط یک WAF بالادستی رد میشود.
- وبهوک در نهایت میرسد اما ۳۰+ ثانیه طول میکشد، که در آن مدت مشتری صفحه صورتحساب را دوباره بارگذاری کرده و نگران میشود.
تطابقدهنده idempotent است — فراخوانی آن در هر بار بارگذاری صفحه ایمن است. وبهوک همچنان همان کار را زمانی که میرسد انجام میدهد؛ دو مسیر در یک ردیف در plan_subscriptions همگرا میشوند.
پلنهای سفارشی
پلنهایی با price_cents = 0 به معنای رایگان در مفهوم مشتری نیستند — آنها فقط محلی هستند، هرگز به Stripe همگامسازی نمیشوند و برای معاملات دستی سازمانی یا جایگزینی پلن رایگان استفاده میشوند. مدیران آنها را به همان روش ایجاد میکنند؛ همگامسازی Stripe بهسادگی از آنها رد میشود.