4.6 KiB
4.6 KiB
پایگاه داده — تسک ۱۱: پنل اشتراکی (Subscription Tiers)
جدول: subscription_plans
| ستون | نوع | توضیح |
|---|---|---|
| id | INT UNSIGNED AUTO_INCREMENT PK | |
| uuid | CHAR(36) UNIQUE NOT NULL | |
| name | VARCHAR(30) NOT NULL | 'free' | 'basic' | 'professional' |
| level | TINYINT NOT NULL | 0, 1, یا 2 |
| max_secretaries | TINYINT NOT NULL | 1, 2، یا 5 |
| features | JSON NOT NULL | {"patient_records": bool, "services": bool, "sms_panel": bool} |
| active | TINYINT(1) NOT NULL DEFAULT 1 | |
| created_at | INT NOT NULL | Unix timestamp |
| updated_at | INT NOT NULL | Unix timestamp |
جدول: subscription_periods
| ستون | نوع | توضیح |
|---|---|---|
| id | INT UNSIGNED AUTO_INCREMENT PK | |
| uuid | CHAR(36) UNIQUE NOT NULL | |
| plan_id | INT NOT NULL FK→subscription_plans.id ON DELETE CASCADE | |
| label | VARCHAR(50) NOT NULL | مثال: '۶ ماهه', 'تریال ۱ ماهه' |
| duration_months | TINYINT NOT NULL | مدت به ماه |
| price_rials | INT NOT NULL | 0 برای تریال |
| is_trial | TINYINT(1) NOT NULL DEFAULT 0 | |
| active | TINYINT(1) NOT NULL DEFAULT 1 | |
| sort_order | TINYINT NOT NULL DEFAULT 0 | ترتیب نمایش |
| created_at | INT NOT NULL | |
| updated_at | INT NOT NULL |
جدول: clinic_subscriptions
| ستون | نوع | توضیح |
|---|---|---|
| id | INT UNSIGNED AUTO_INCREMENT PK | |
| uuid | CHAR(36) UNIQUE NOT NULL | |
| entity_type | VARCHAR(10) NOT NULL | 'doctor' | 'clinic' |
| entity_id | INT NOT NULL | id دکتر یا کلینیک |
| plan_id | INT NOT NULL FK→subscription_plans.id | |
| period_id | INT NOT NULL FK→subscription_periods.id | |
| payment_id | INT NULL FK→payments.id ON DELETE SET NULL | NULL برای تریال |
| is_trial | TINYINT(1) NOT NULL DEFAULT 0 | |
| starts_at | INT NOT NULL | Unix timestamp |
| expires_at | INT NULL | NULL = بینهایت (Free) |
| created_at | INT NOT NULL |
ایندکسها
-- جستجوی سریع اشتراک فعال
CREATE INDEX idx_clinic_subscriptions_entity
ON clinic_subscriptions(entity_type, entity_id, expires_at);
-- جلوگیری از استفاده مکرر از تریال
-- توجه: این constraint روی is_trial=1 کار میکند چون is_trial=0 میتواند تکراری باشد
-- بنابراین در application check میکنیم نه UNIQUE index
CREATE INDEX idx_clinic_subscriptions_trial
ON clinic_subscriptions(entity_type, entity_id, is_trial);
Seed Data (Migration اولیه)
-- سه پنل پایه — باید در migration ایجاد شوند
INSERT INTO subscription_plans (uuid, name, level, max_secretaries, features, active, created_at, updated_at) VALUES
(UUID(), 'free', 0, 1, '{"patient_records":false,"services":false,"sms_panel":false}', 1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
(UUID(), 'basic', 1, 2, '{"patient_records":true,"services":true,"sms_panel":false}', 1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
(UUID(), 'professional', 2, 5, '{"patient_records":true,"services":true,"sms_panel":true}', 1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
-- دورههای نمونه برای basic (ادمین بعداً قیمتها را ویرایش میکند)
-- plan_id=2 = basic
INSERT INTO subscription_periods (uuid, plan_id, label, duration_months, price_rials, is_trial, active, sort_order, created_at, updated_at) VALUES
(UUID(), 2, 'تریال ۱ ماهه', 1, 0, 1, 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
(UUID(), 2, '۱ ماهه', 1, 250000, 0, 1, 1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
(UUID(), 2, '۳ ماهه', 3, 690000, 0, 1, 2, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
(UUID(), 2, '۶ ماهه', 6, 1200000, 0, 1, 3, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
(UUID(), 2, '۱۲ ماهه', 12, 2000000, 0, 1, 4, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
SiteConfig key های جدید
| کلید | نوع | مقدار پیشفرض | توضیح |
|---|---|---|---|
trial_enabled |
string '1'|'0' |
'1' |
ادمین میتواند تریال را غیرفعال کند |
نکات مهم
expires_at = NULLفقط برای رکوردهای Free plan است — اینها بینهایت معتبرند- query اشتراک فعال:
WHERE entity_type=? AND entity_id=? AND (expires_at IS NULL OR expires_at > UNIX_TIMESTAMP()) ORDER BY id DESC LIMIT 1 - تریال check در application:
SELECT COUNT(*) FROM clinic_subscriptions WHERE entity_type=? AND entity_id=? AND is_trial=1