Soft Delete بهجای حذف فیزیکی
عملیات «حذف» در واقع فقط پرچم is_active را False میکند. این تصمیم مستقیماً از نیازمندی سند پروژه («غیرفعال کردن اپلیکیشن») گرفته شده و تضمین میکند دادههای تاریخی (ریویوها، آمار) هرگز از دست نروند.
معماری، فلوی درخواستها و تصمیمات مهندسی زیرسیستم مدیریت اپلیکیشنها
این مستند معماری، فلوی درخواستها، و تصمیمات مهندسی زیرسیستم مدیریت لیست اپلیکیشنها را که با Django REST Framework پیادهسازی شده، شرح میدهد. این زیرسیستم مسئول عملیات Create/Read/Update/Deactivate روی فهرست اپلیکیشنهای تحت پایش پروژه است و بهعنوان منبع حقیقت (Source of Truth) برای زیرسیستم کراولر عمل میکند.
بهجای نوشتن منطق کسبوکار مستقیم داخل Viewها (اشتباه رایج در پروژههای Django)، این زیرسیستم بر اساس یک معماری لایهای سبک طراحی شده که مسئولیتها را طبق اصل Single Responsibility Principle جدا میکند.
| لایه | مسئولیت | چرا جدا شده |
|---|---|---|
| View | دریافت Request، صدا زدن Service، بازگرداندن Response | هیچ تصمیم کسبوکاری در این لایه گرفته نمیشود؛ فقط Orchestration خالص HTTP |
| Serializer | اعتبارسنجی فرمت ورودی (مثل فرمت package_name) | قوانین فرمت داده از قوانین کسبوکار (مثل یکتایی) جدا شدهاند |
| Service | منطق کسبوکار (یکتایی، Soft Delete، تغییرناپذیری package_name) | قابل استفاده مستقل از HTTP؛ مثلاً از CLI یا Celery هم قابل فراخوانی است |
| Exception | خطاهای دامنه با معنای مشخص (AlreadyExists, NotFound, Invalid) | جایگزین خطاهای عمومی و بیمعنی؛ توسط Handler مرکزی به کد HTTP مناسب map میشود |
| Model | تعریف ساختار داده و ارتباط با پایگاهداده | تنها لایهای که مستقیماً با ORM/دیتابیس در ارتباط است |
این دیاگرام دقیقترین مسیر یک درخواست را در سیستم نشان میدهد — از لحظهی ورود Request تا برگشت Response، شامل مسیر شکست (خطا) در صورت تکراری بودن.
این عملیات بهصورت Idempotent طراحی شده است — یعنی فراخوانی مکرر آن روی یک اپ از قبل غیرفعال، همچنان با موفقیت (نه خطا) پاسخ میدهد. این تصمیم آگاهانه از اصول طراحی REST پیروی میکند.
| Method | مسیر | عملکرد | کدهای پاسخ |
|---|---|---|---|
| GET | /api/applications/ | لیست اپلیکیشنها، با فیلتر اختیاری (is_active, is_messaging_app, category) | 200 |
| POST | /api/applications/ | ساخت اپلیکیشن جدید | 201, 400, 409 |
| GET | /api/applications/{id}/ | دریافت جزئیات یک اپلیکیشن | 200, 404 |
| PATCH / PUT | /api/applications/{id}/ | ویرایش اپلیکیشن (package_name غیرقابلتغییر است) | 200, 400, 404 |
| POST | /api/applications/{id}/deactivate/ | غیرفعالسازی (Soft Delete، Idempotent) | 200, 404 |
| POST | /api/applications/{id}/reactivate/ | فعالسازی مجدد (Idempotent) | 200, 404 |
مستندات تعاملی و کامل این Endpointها بهصورت خودکار (Swagger/OpenAPI) در آدرس /swagger/ در دسترس است و شامل نمونهی Request/Response برای هر عملیات میباشد.
عملیات «حذف» در واقع فقط پرچم is_active را False میکند. این تصمیم مستقیماً از نیازمندی سند پروژه («غیرفعال کردن اپلیکیشن») گرفته شده و تضمین میکند دادههای تاریخی (ریویوها، آمار) هرگز از دست نروند.
فراخوانی مکرر این عملیاتها خطا تولید نمیکند، طبق بهترینشیوههای طراحی REST API؛ کلاینت نیازی به بررسی وضعیت فعلی قبل از فراخوانی ندارد.
این فیلد شناسهی ارجاعی تمام زیرسیستمهای دیگر (کراولر، صف پیام) است؛ به همین دلیل پس از ساخت اولیه غیرقابلتغییر است. این قانون هم در Serializer (فیلد read-only در ویرایش) و هم در Service (بررسی صریح) اعمال شده — دفاع دو لایهای در برابر خطای انسانی یا برنامهنویسی.
بهجای تکرار try/except در هر View، خطاهای دامنه (ApplicationAlreadyExistsException، ApplicationNotFoundException، ...) توسط یک Exception Handler مرکزی به کد HTTP مناسب (409، 404، 400) نگاشت میشوند. این معماری از اصل DRY و Open/Closed Principle پیروی میکند: افزودن خطای جدید نیازی به تغییر Viewهای موجود ندارد.
این یک تصمیم آگاهانه است، نه کمبود. Django ذاتاً بر پایهی الگوی Active Record ساخته شده و DI کامل (تزریق Repository بهجای دسترسی مستقیم ORM) در این مقیاس هزینهی مهندسی بیشتری نسبت به فایدهاش دارد؛ بهخصوص که استراتژی تست این پروژه بر پایهی Integration Test با دیتابیس واقعی است، نه Unit Test کاملاً مجزا با Mock.
تستها مطابق اصل Test Pyramid، از پایینترین لایه به بالاترین لایه نوشته شدهاند تا هم سرعت اجرا و هم پوشش کامل مسیر HTTP تضمین شود.
| لایهی تست | نمونه سناریوهای پوششدادهشده |
|---|---|
| Serializer | فرمت نامعتبر package_name (بدون نقطه، فاصلهدار، نقطهی ابتدایی/انتهایی)، display_name فقطفاصله |
| Service | ساخت موفق/تکراری، فیلتر بر اساس وضعیت و دسته، تغییرناپذیری package_name، رفتار Idempotent در Deactivate/Reactivate، چرخهی کامل حیات یک اپلیکیشن |
| View | کدهای وضعیت HTTP صحیح برای هر سناریو (۲۰۰، ۲۰۱، ۴۰۰، ۴۰۴، ۴۰۹)، فیلتر از طریق Query Parameter |
| ابزار | نقش |
|---|---|
| Django + Django REST Framework | فریمورک اصلی و لایهی API |
| PostgreSQL | پایگاهدادهی رابطهای |
| drf-yasg | تولید خودکار مستندات Swagger/OpenAPI |
| Django TestCase / DRF APITestCase | تستهای Unit و Integration |
| python-dotenv | مدیریت پیکربندی محیطی (env variables) |
این زیرسیستم بهعنوان اولین ماژول کاملاً پیادهسازیشدهی پروژه، پایهی الگوی معماری (Service Layer + Exception Handling مرکزی) را برای زیرسیستمهای بعدی (کراولر، تحلیل شبکه) نیز فراهم میکند.