← مجموعه مستندات پروژه
TECHNICAL DOCUMENTATION

زیرسیستم ذخیره لیست اپلیکیشن‌ها (Application Registry)

معماری، فلوی درخواست‌ها و تصمیمات مهندسی زیرسیستم مدیریت اپلیکیشن‌ها

این مستند معماری، فلوی درخواست‌ها، و تصمیمات مهندسی زیرسیستم مدیریت لیست اپلیکیشن‌ها را که با Django REST Framework پیاده‌سازی شده، شرح می‌دهد. این زیرسیستم مسئول عملیات Create/Read/Update/Deactivate روی فهرست اپلیکیشن‌های تحت پایش پروژه است و به‌عنوان منبع حقیقت (Source of Truth) برای زیرسیستم کراولر عمل می‌کند.

۱ معماری لایه‌ای

به‌جای نوشتن منطق کسب‌وکار مستقیم داخل Viewها (اشتباه رایج در پروژه‌های Django)، این زیرسیستم بر اساس یک معماری لایه‌ای سبک طراحی شده که مسئولیت‌ها را طبق اصل Single Responsibility Principle جدا می‌کند.

flowchart TD A[HTTP Request] --> B["View Layer
(orchestration only)"] B --> C["Serializer Layer
(format validation)"] B --> D["Service Layer
(business logic)"] D --> E["Exception Layer
(semantic errors)"] D --> F["Model Layer
(Django ORM)"] F --> G[(PostgreSQL)] D --> B B --> H[HTTP Response] style B fill:#2563eb,color:#fff style D fill:#16a34a,color:#fff style C fill:#f59e0b,color:#fff style E fill:#dc2626,color:#fff style F fill:#7c3aed,color:#fff
لایهمسئولیتچرا جدا شده
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/دیتابیس در ارتباط است

۲ فلوی درخواست: ساخت اپلیکیشن جدید (Create)

این دیاگرام دقیق‌ترین مسیر یک درخواست را در سیستم نشان می‌دهد — از لحظه‌ی ورود Request تا برگشت Response، شامل مسیر شکست (خطا) در صورت تکراری بودن.

sequenceDiagram participant Client participant View as ApplicationListCreateView participant Serializer as ApplicationSerializer participant Service as ApplicationService participant DB as PostgreSQL Client->>View: POST /api/applications/ View->>Serializer: validate(data) alt فرمت نامعتبر (مثلاً بدون نقطه) Serializer-->>View: ValidationError View-->>Client: 400 Bad Request else فرمت معتبر Serializer-->>View: validated_data View->>Service: create_application(...) Service->>DB: SELECT WHERE package_name=... alt package_name تکراری است DB-->>Service: exists Service-->>View: raise ApplicationAlreadyExistsException View-->>Client: 409 Conflict else package_name جدید است DB-->>Service: not exists Service->>DB: INSERT INTO applications DB-->>Service: created record Service-->>View: Application instance View-->>Client: 201 Created end end

۳ فلوی درخواست: غیرفعال‌سازی اپلیکیشن (Deactivate)

این عملیات به‌صورت Idempotent طراحی شده است — یعنی فراخوانی مکرر آن روی یک اپ از قبل غیرفعال، همچنان با موفقیت (نه خطا) پاسخ می‌دهد. این تصمیم آگاهانه از اصول طراحی REST پیروی می‌کند.

sequenceDiagram participant Client participant View as ApplicationDeactivateView participant Service as ApplicationService participant DB as PostgreSQL Client->>View: POST /api/applications/{id}/deactivate/ View->>Service: deactivate_application(id) Service->>DB: SELECT WHERE id=... alt اپلیکیشن یافت نشد DB-->>Service: DoesNotExist Service-->>View: raise ApplicationNotFoundException View-->>Client: 404 Not Found else اپلیکیشن یافت شد DB-->>Service: Application instance Service->>Service: is_active = False Service->>DB: UPDATE applications Note over Service: بدون توجه به وضعیت قبلی،
عملیات با موفقیت کامل می‌شود (Idempotent) DB-->>Service: saved Service-->>View: Application instance View-->>Client: 200 OK end

۴ نقشه‌ی کامل Endpointها

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 برای هر عملیات می‌باشد.

۵ تصمیمات کلیدی طراحی

Soft Delete به‌جای حذف فیزیکی

عملیات «حذف» در واقع فقط پرچم is_active را False می‌کند. این تصمیم مستقیماً از نیازمندی سند پروژه («غیرفعال کردن اپلیکیشن») گرفته شده و تضمین می‌کند داده‌های تاریخی (ریویوها، آمار) هرگز از دست نروند.

Idempotent بودن Deactivate/Reactivate

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

تغییرناپذیری package_name

این فیلد شناسه‌ی ارجاعی تمام زیرسیستم‌های دیگر (کراولر، صف پیام) است؛ به همین دلیل پس از ساخت اولیه غیرقابل‌تغییر است. این قانون هم در Serializer (فیلد read-only در ویرایش) و هم در Service (بررسی صریح) اعمال شده — دفاع دو لایه‌ای در برابر خطای انسانی یا برنامه‌نویسی.

مدیریت خطای دامنه به‌صورت مرکزی

به‌جای تکرار try/except در هر View، خطاهای دامنه (ApplicationAlreadyExistsException، ApplicationNotFoundException، ...) توسط یک Exception Handler مرکزی به کد HTTP مناسب (409، 404، 400) نگاشت می‌شوند. این معماری از اصل DRY و Open/Closed Principle پیروی می‌کند: افزودن خطای جدید نیازی به تغییر Viewهای موجود ندارد.

عدم استفاده از Dependency Injection کلاسیک

این یک تصمیم آگاهانه است، نه کمبود. Django ذاتاً بر پایه‌ی الگوی Active Record ساخته شده و DI کامل (تزریق Repository به‌جای دسترسی مستقیم ORM) در این مقیاس هزینه‌ی مهندسی بیشتری نسبت به فایده‌اش دارد؛ به‌خصوص که استراتژی تست این پروژه بر پایه‌ی Integration Test با دیتابیس واقعی است، نه Unit Test کاملاً مجزا با Mock.

۶ استراتژی تست

تست‌ها مطابق اصل Test Pyramid، از پایین‌ترین لایه به بالاترین لایه نوشته شده‌اند تا هم سرعت اجرا و هم پوشش کامل مسیر HTTP تضمین شود.

flowchart TD A["Serializer Tests
(فرمت ورودی)"] --> B["Service Tests
(منطق کسب‌وکار، مستقل از HTTP)"] B --> C["View Tests
(کل مسیر HTTP، با APITestCase)"] style A fill:#f59e0b,color:#fff style B fill:#16a34a,color:#fff style C fill:#2563eb,color:#fff
لایه‌ی تستنمونه سناریوهای پوشش‌داده‌شده
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 مرکزی) را برای زیرسیستم‌های بعدی (کراولر، تحلیل شبکه) نیز فراهم می‌کند.