22 KiB
معماری نرمافزار (Software Architecture) – سامانه مدیریت و گزارش خرابی دانشگاهی
تهیهکننده: ارشیا همتیزاده
بازبین: رضا آدوسی
آخرین بهروزرسانی: ۱۴۰۵/۰۸/۱۴
مقدمه
این سند معماری نرمافزاری سامانهٔ مدیریت و گزارش خرابی دانشگاهی را در سطح منطقی و مفهومی تعریف میکند. چون پروژه هنوز وارد فاز پیادهسازی نشده است (طبق README.md)، این سند تعهد به فناوری خاصی ندارد و انتخابهای فناورانه در بخش «پرسشهای باز» علامتگذاری شدهاند.
هدف این سند پاسخ به سه پرسش است:
- سامانه از چه مؤلفههایی تشکیل میشود و مرز مسئولیت هر کدام کجاست؟
- این مؤلفهها چگونه با هم همکاری میکنند تا جریانهای توصیفشده در
activity.mdمحقق شوند؟ - کدام نیروهای محرک معماری (Architectural Drivers) این ساختار را توجیه میکنند؟
۱. نیروهای محرک معماری
۱.۱. نیازمندیهای غیرکارکردی
| شناسه | نیازمندی | اثر معماری |
|---|---|---|
NFR-01 |
امنیت اطلاعات | احراز هویت متمرکز، مجوزدهی سمت سرور، هش رمز، جلوگیری از دسترسی مستقیم به صفحات نقش دیگر |
NFR-02 |
حفظ حریم خصوصی | فیلتر داده بر اساس نقش در لایهٔ برنامه (نه فقط در رابط کاربری) |
NFR-03 |
کاربردپذیری | رابط RTL فارسی، اعتبارسنجی درجا، پیام خطای روشن |
NFR-04 |
زمان پاسخگویی | ایندکسگذاری هدفمند (طبق data-model.md §۷)، پرهیز از کوئریهای سنگین در داشبورد |
NFR-05 |
صحت و نگهداری اطلاعات | تاریخچهٔ append-only، قفل خوشبینانه، تراکنشهای اتمیک |
NFR-06 |
قابلیت نگهداری و توسعه | معماری لایهای و ماژولار، جداسازی دامنه از زیرساخت |
۱.۲. محدودیتها
| محدودیت | منبع | اثر |
|---|---|---|
| تیم سهنفره، پروژهٔ دانشگاهی | README.md |
پرهیز از معماریهای توزیعشده و پیچیده |
| هنوز فناوری انتخاب نشده | README.md («هنوز کدنویسی و پیادهسازی انجام نشده») |
معماری باید فناوریمستقل بماند |
| فهرست وضعیتها و اولویتها نهایی نیست | پرسشهای باز ۳ و ۴ در activity.md |
اینها باید داده باشند، نه کد |
| دامنهٔ فضاها مشخص نیست | ابهام README.md |
مدل محل خرابی باید قابل گسترش بماند |
۲. سبک معماری انتخابشده
سبک پیشنهادی: مونولیت ماژولار لایهای (Modular Layered Monolith)
۲.۱. مقایسهٔ گزینهها
| گزینه | مزیت | عیب | تناسب با این پروژه |
|---|---|---|---|
| مونولیت لایهای | سادگی استقرار، دیباگ آسان، مناسب تیم کوچک | مقیاسپذیری مستقل ماژولها ندارد | ✅ انتخاب شد |
| میکروسرویس | استقلال استقرار، مقیاسپذیری انتخابی | هزینهٔ عملیاتی بالا، نیاز به DevOps، پیچیدگی تراکنش توزیعشده | ❌ برای تیم سهنفره و پروژهٔ درسی توجیه ندارد |
| بدون لایه (اسکریپتمحور) | سرعت شروع | نقض NFR-06، عدم قابلیت نگهداری |
❌ |
۲.۲. توجیه
NFR-06قابلیت نگهداری را الزام میکند؛ لایهبندی این را تضمین میکند.NFR-05صحت داده را الزام میکند؛ تراکنش در یک پایگاهدادهٔ واحد بسیار سادهتر از تراکنش توزیعشده است.- مرزهای دامنه (بخش ۳) از
domain-model.mdگرفته شدهاند تا در آیندهٔ دور اگر لازم شد، جداسازی به میکروسرویس ممکن باشد، بدون بازنویسی دامنه.
۳. مرزهای ماژول (Bounded Contexts)
مرزها از domain-model.md §۱ گرفته شدهاند:
| ماژول | مسئولیت | مفاهیم اصلی | نیازمندیها |
|---|---|---|---|
| M1 — هویت و دسترسی | احراز هویت، تشخیص نقش، مجوزدهی | کاربر، نقش، نشست | FR-01، FR-02، US-15 |
| M2 — گزارش خرابی | ثبت، پیگیری، اطلاعات تکمیلی، بازخورد گزارشدهنده | گزارش، اطلاعات تکمیلی، بازخورد | FR-03–FR-05، FR-14، US-01–US-05 |
| M3 — مدیریت تعمیر | بررسی، اولویتبندی، تخصیص، ثبت نتیجه | اولویت، تخصیص، نتیجهٔ تعمیر | FR-06–FR-13، US-06–US-14 |
| M4 — اطلاعرسانی | واکنش به رویدادهای دامنه و ارسال اعلان | اعلان، کانال | FR-15، US-16 |
| M5 — نظارت | داشبورد و آمار تجمیعی | داشبورد (Read Model) | FR-17، US-17 |
نکته: M2 و M3 در
data-model.mdروی یک جدول مرکزی (fault_reports) کار میکنند. جداسازی این دو ماژول منطقی است، نه فیزیکی. مزیت: هر ماژول فقط متدهای مجاز خودش را روی گزارش فراخوانی میکند و قانون «تغییر وضعیت فقط از مسیر مجاز» در یک نقطه کنترل میشود.
۴. لایههای معماری
flowchart TB
subgraph P["لایهٔ نمایش (Presentation)"]
P1["رابط وب RTL<br/>SCR-01 تا SCR-12"]
end
subgraph A["لایهٔ برنامه (Application)"]
A1["سرویسهای کاربردی<br/>Use Cases"]
A2["اعتبارسنجی ورودی"]
A3["کنترل دسترسی"]
end
subgraph D["لایهٔ دامنه (Domain)"]
D1["موجودیتها و Value Objectها"]
D2["سیاستهای دامنه"]
D3["ماشین حالت گزارش"]
D4["رویدادهای دامنه"]
end
subgraph I["لایهٔ زیرساخت (Infrastructure)"]
I1["دسترسی به داده"]
I2["سرویس احراز هویت"]
I3["ارسال اعلان"]
I4["ذخیرهسازی فایل"]
end
P --> A
A --> D
A --> I
D -.->|"بدون وابستگی به زیرساخت"| I
classDef pres fill:#e3f2fd,stroke:#1565c0
classDef app fill:#fff3e0,stroke:#ef6c00
classDef dom fill:#e8f5e9,stroke:#2e7d32
classDef inf fill:#f3e5f5,stroke:#6a1b9a
class P1 pres
class A1,A2,A3 app
class D1,D2,D3,D4 dom
class I1,I2,I3,I4 inf
قاعدهٔ وابستگی: جهت وابستگی همیشه به سمت دامنه است. دامنه به هیچ لایهٔ دیگری وابسته نیست. این قاعده NFR-06 را تضمین میکند و اجازه میدهد در آینده پایگاهداده یا سرویس احراز هویت عوض شود بدون تغییر منطق کسبوکار.
۵. نمای ظرف (Container View)
flowchart TB
subgraph Client["مرورگر کاربر"]
C1["برنامهٔ وب<br/>(رابط RTL فارسی)"]
end
subgraph Server["سرور برنامه"]
S1["API / لایهٔ برنامه"]
S2["ماژولهای M1 تا M5"]
S3["کارگر پسزمینه<br/>(پردازش رویدادها)"]
end
subgraph Data["لایهٔ داده"]
DB[("پایگاهدادهٔ رابطهای<br/>مرجع: PostgreSQL")]
FS[("ذخیرهسازی فایل<br/>تصاویر اطلاعات تکمیلی")]
end
subgraph External["سرویسهای بیرونی"]
AUTH["سرویس احراز هویت"]
NOTIF["درگاه اعلان<br/>(درونبرنامه / پیامک / ایمیل)"]
end
C1 -->|"HTTPS / JSON"| S1
S1 --> S2
S2 --> DB
S2 --> FS
S2 --> AUTH
S2 -.->|"انتشار رویداد"| S3
S3 --> NOTIF
classDef ext fill:#fff8e1,stroke:#f9a825,stroke-dasharray: 4 4
class AUTH,NOTIF ext
توضیح: پردازش اعلان (M4) بهصورت غیرهمگام از طریق رویداد انجام میشود تا
NFR-04حفظ شود: ثبت گزارش نباید منتظر ارسال پیامک بماند. کانال دقیق اعلان هنوز پرسش باز ۸ است؛ بنابراینNOTIFبهعنوان یک آداپتور قابل تعویض مدل شده است.
۶. جریانهای کلیدی
۶.۱. ورود به سامانه (AD-01، US-15)
sequenceDiagram
actor U as کاربر
participant UI as رابط کاربری
participant APP as لایهٔ برنامه
participant AUTH as سرویس احراز هویت
participant DB as پایگاهداده
U->>UI: نام کاربری و رمز عبور
UI->>UI: بررسی فیلد خالی
alt فیلد خالی
UI-->>U: «این فیلد الزامی است»
else کامل
UI->>APP: درخواست ورود
APP->>AUTH: اعتبارسنجی
alt سرویس در دسترس نیست
AUTH-->>APP: خطا
APP-->>UI: «خطا در ورود؛ لطفاً بعداً تلاش کنید»
else پاسخ دریافت شد
AUTH-->>APP: نتیجه
alt نامعتبر
APP-->>UI: «نام کاربری یا رمز عبور اشتباه است»
UI-->>U: خطای مبهم (بدون افشای فیلد اشتباه)
else معتبر
APP->>DB: ثبت رویداد ورود
APP-->>UI: نشست + نقش
UI-->>U: داشبورد متناسب با نقش
end
end
end
الزامات امنیتی بازتابیافته: پیام خطا نباید مشخص کند کدام فیلد اشتباه است (US-15.feature). این قاعده در لایهٔ برنامه اعمال میشود، نه در رابط کاربری.
۶.۲. ثبت گزارش خرابی (AD-02، US-01، US-02)
sequenceDiagram
actor R as گزارشدهنده
participant UI as رابط کاربری
participant APP as لایهٔ برنامه
participant DOM as دامنه
participant DB as پایگاهداده
R->>UI: پر کردن فرم
UI->>UI: اعتبارسنجی سمت کلاینت
Note over UI: اجباری: عنوان، توضیحات، محل، نوع تجهیز<br/>حداکثر عنوان: ۱۵۰ کاراکتر
alt نامعتبر
UI-->>R: نمایش خطا کنار فیلد، حفظ مقادیر
else معتبر
UI->>APP: ارسال
APP->>APP: کنترل دسترسی (نقش مجاز)
APP->>DOM: اعتبارسنجی مجدد
alt نامعتبر
DOM-->>APP: نقض قاعده
APP-->>UI: خطای اعتبارسنجی
UI-->>R: نمایش خطا
else معتبر
APP->>DB: درج گزارش (وضعیت: ثبتشده)
APP->>DB: درج رویداد تاریخچه REPORT_SUBMITTED
APP-->>UI: شناسهٔ گزارش
UI-->>R: پیام موفقیت + شناسهٔ یکتا
APP-)APP: انتشار ReportSubmitted
end
end
نکتهٔ مهم (الزام US-01.feature): «اعتبارسنجی سمت کلاینت» فقط برای تجربهٔ کاربری است. اعتبارسنجی معتبر در لایهٔ برنامه و دامنه انجام میشود. اگر درخواست مستقیماً به API ارسال شود، همان قواعد باید اعمال شوند.
۶.۳. تخصیص تعمیرکار (AD-03، US-08)
sequenceDiagram
actor F as کارمند تأسیسات
participant APP as لایهٔ برنامه
participant DOM as دامنه
participant DB as پایگاهداده
participant N as ماژول اطلاعرسانی
F->>APP: انتخاب گزارش + تعمیرکار
APP->>APP: کنترل دسترسی
APP->>DOM: درخواست تخصیص
DOM->>DOM: بررسی وضعیت مجاز
alt وضعیت مجاز نیست
DOM-->>APP: خطا
APP-->>F: پیام خطا
else مجاز
DOM->>DB: درج تخصیص
DOM->>DB: تغییر وضعیت به ارجاعشده
DOM->>DB: درج رویداد تاریخچه TECHNICIAN_ASSIGNED
DOM-)N: انتشار TechnicianAssigned
N->>N: ارسال اعلان (غیرهمگام)
APP-->>F: پیام موفقیت
end
۶.۴. تأیید یا رد تعمیر (AD-05، US-05)
sequenceDiagram
actor R as گزارشدهنده
participant APP as لایهٔ برنامه
participant DOM as دامنه
participant DB as پایگاهداده
R->>APP: درخواست تأیید/رد
APP->>APP: کنترل دسترسی
APP->>DB: خواندن گزارش با قفل خوشبینانه
APP->>DOM: بررسی قواعد تأیید
DOM->>DOM: ۱) کاربر = گزارشدهندهٔ همان گزارش؟<br/>۲) وضعیت = تعمیر انجامشده؟<br/>۳) آیا قبلاً بازخورد ثبت شده؟
alt یکی از شروط نقض شد
DOM-->>APP: رد درخواست
APP-->>R: پیام متناسب
Note over APP,R: «دسترسی مجاز نیست» یا<br/>«این گزارش در وضعیت قابل تأیید نیست»
else مجاز
alt رد بدون دلیل
APP-->>R: «ذکر دلیل رد الزامی است»
else
APP->>DB: درج بازخورد (UNIQUE روی نتیجهٔ تعمیر)
APP->>DB: درج رویداد تاریخچه
alt تأیید
APP->>DB: تغییر وضعیت به بستهشده + closed_at
end
APP-->>R: پیام موفقیت
end
end
چرا قفل خوشبینانه؟ الزام ایدمپوتنسی در US-05.feature: «کلیک دوباره روی تأیید یک تغییر وضعیت بیشتر ایجاد نمیکند». ترکیب UNIQUE (report_id, repair_result_id) در data-model.md و بررسی version تضمین دوگانه میدهد.
۷. دغدغههای عرضی (Cross-Cutting Concerns)
| دغدغه | راهکار | لایه | مستند مرجع |
|---|---|---|---|
| احراز هویت | سرویس متمرکز؛ در صورت در دسترس نبودن، پیام «خطا در ورود؛ لطفاً بعداً تلاش کنید» و عدم ورود | برنامه | FR-01، US-15.feature |
| مجوزدهی | کنترل سمت سرور در هر درخواست؛ هرگز فقط مخفیکردن دکمه در رابط کاربری | برنامه | FR-02، US-15.feature |
| اعتبارسنجی | دو لایه: رابط کاربری (تجربهٔ کاربری) و دامنه (اعتبار واقعی) | نمایش + دامنه | US-01.feature |
| ثبت تاریخچه | هر تغییر معنادار یک ردیف در report_history؛ append-only |
برنامه + داده | FR-16، NFR-05 |
| رویدادهای دامنه | انتشار پس از commit موفق؛ مصرف غیرهمگام | دامنه → اطلاعرسانی | FR-15 |
| مدیریت خطا | خطاهای قابل نمایش (اعتبارسنجی/مجوز) در برابر خطاهای فنی؛ در خطای فنی، پیام عمومی و ثبت جزئیات در لاگ | برنامه | US-01.feature |
| زمان | همهٔ زمانها با منطقهٔ زمانی (timestamptz) |
داده | data-model.md §۹ |
| تراکنش | تغییر وضعیت + درج تاریخچه در یک تراکنش | برنامه + داده | NFR-05 |
۸. تصمیمهای معماری (ADR)
| شناسه | تصمیم | جایگزین ردشده | دلیل |
|---|---|---|---|
| ADR-01 | مونولیت ماژولار | میکروسرویس | تیم سهنفره، نیاز به تراکنش اتمیک، NFR-06 |
| ADR-02 | معماری لایهای با وابستگی به سمت دامنه | لایهبندی بدون قاعده | جلوگیری از نشت منطق کسبوکار به رابط کاربری |
| ADR-03 | مجوزدهی سمت سرور در هر درخواست | فقط مخفیکردن در رابط کاربری | FR-02، US-15.feature (سناریوی دسترسی مستقیم به آدرس) |
| ADR-04 | اعلان بر پایهٔ رویداد دامنه و غیرهمگام | فراخوانی مستقیم ارسال اعلان در همان تراکنش | NFR-04، جداسازی M4 از M2/M3 |
| ADR-05 | قفل خوشبینانه (version) |
قفل بدبینانه | ایدمپوتنسی US-05.feature بدون بلوکهکردن |
| ADR-06 | فهرست وضعیتها و انتقالها بهصورت داده | ENUM یا switch در کد |
پرسشهای باز ۳ و ۴ هنوز بسته نشدهاند |
| ADR-07 | تاریخچهٔ append-only | لاگ فایل یا audit سطح پایگاهداده |
قابل مشاهده برای کاربر (FR-16، US-10) |
| ADR-08 | شناسههای فنی انگلیسی، متن رابط فارسی | همهچیز فارسی | تعارض با CONTRIBUTING.md ندارد؛ آن بند دربارهٔ متن مستندات است |
۹. نمای استقرار (Deployment View)
flowchart LR
subgraph Browser["دستگاه کاربر"]
B1["مرورگر"]
end
subgraph Host["میزبان (تکسرور یا Docker Compose)"]
W1["سرور برنامه"]
D1[("پایگاهداده")]
F1[("ذخیرهسازی فایل")]
end
B1 -->|HTTPS| W1
W1 --> D1
W1 --> F1
classDef future fill:#f5f5f5,stroke:#9e9e9e,stroke-dasharray: 4 4
فرض: برای یک پروژهٔ دانشگاهی، استقرار تکسروری (یا docker compose با سه سرویس) کافی است. جزئیات فناورانه در پرسشهای باز آمدهاند.
۱۰. نگاشت نیازمندیهای غیرکارکردی به راهکار معماری
| NFR | راهکار معماری | محل تحقق |
|---|---|---|
NFR-01 امنیت |
احراز هویت متمرکز، مجوزدهی سمت سرور، هش رمز، عدم افشای فیلد اشتباه | M1، لایهٔ برنامه |
NFR-02 حریم خصوصی |
فیلتر نتایج بر اساس نقش در سرویسهای کاربردی | لایهٔ برنامه |
NFR-03 کاربردپذیری |
رابط RTL، اعتبارسنجی درجا، پیامهای دقیق | لایهٔ نمایش (ui-wireframes.md) |
NFR-04 زمان پاسخ |
ایندکسهای data-model.md §۷، اعلان غیرهمگام، داشبورد بهصورت نمای تجمیعی |
داده + M4 + M5 |
NFR-05 صحت داده |
تراکنش اتمیک، تاریخچهٔ append-only، قفل خوشبینانه، ممنوعیت حذف فیزیکی | دامنه + داده |
NFR-06 نگهداشت |
لایهبندی، مرز ماژول، جداسازی دامنه از زیرساخت، ADRها | کل معماری |
۱۱. ریسکهای معماری
| # | ریسک | اثر | کاهش |
|---|---|---|---|
| R1 | بستهنشدن پرسش باز ۹ (چند نقش برای کاربر) | تغییر در M1 و مدل داده و نمودار کلاس | تصمیمگیری پیش از پیادهسازی؛ در غیر این صورت تغییر سه سند |
| R2 | نهایینشدن فهرست وضعیتها (پرسش ۴) | تغییر ماشین حالت و انتقالهای مجاز | ADR-06: انتقالها بهصورت داده |
| R3 | رشد دامنه به خوابگاه و فضاهای اداری | تأثیر بر مدل محل و مجوزها | مدل محل قابل گسترش (data-model.md D2) |
| R4 | انتخاب نشدن کانال اعلان (پرسش ۸) | تأخیر در M4 |
آداپتور قابل تعویض (بخش ۵) |
| R5 | انتخابنشدن فناوری | عدم شروع پیادهسازی | پرسش باز ۱۶ |
۱۲. نکات و پرسشهای باز
| # | پرسش | نیازمند تصمیم |
|---|---|---|
| ۱۶ | فناوری لایهٔ نمایش، برنامه و داده چیست؟ (زبان، فریمورک، DBMS) | تیم — پیش از فاز پیادهسازی |
| ۱۷ | سرویس احراز هویت داخلی ساخته شود یا از راهکار آماده استفاده شود؟ | تیم |
| ۱۸ | ذخیرهسازی تصاویر اطلاعات تکمیلی در فایلسیستم یا پایگاهداده؟ | تیم |
| ۱۹ | نیاز به API عمومی یا صرفاً مصرف داخلی رابط کاربری؟ | تیم |
| ۲۰ | سطح دسترسی دقیق مدیر (پرسش باز ۹ در activity.md) چه اثری بر M1 و M5 دارد؟ |
تیم |
| ۲۱ | آیا نیاز به ثبت تلاشهای ورود ناموفق و قفل حساب وجود دارد؟ (در مستندات نیامده) | تیم |
| ۲۲ | آیا رابط کاربری باید واکنشگرا (Responsive) باشد؟ (در NFR-03 صریح نیست) |
تیم |
وضعیت سند: نسخه اولیه (Draft) – آماده بازبینی