9 Commits

Author SHA1 Message Date
Arshia f2c0e0aaac modified software-architecture and UI-wireframes 2026-11-05 20:27:23 +03:30
Arshia 47ac8c1f8e added ui-wireframes 2026-11-05 20:22:07 +03:30
Arshia 969d2fa188 added software-architecture 2026-11-05 20:19:55 +03:30
Arshia 45ee92efb0 modified data model again. 2026-11-05 17:05:56 +03:30
Arshia 940e661ba7 modified data model 2026-11-05 16:59:38 +03:30
Arshia 9951ae4568 added data model 2026-11-05 16:58:18 +03:30
Arshia bf1dc6388d modifed class diagram 2026-11-05 12:56:46 +03:30
Arshia 74aea41f21 افزودن نمودار کلاس (class-diagram.md) بر اساس مستندات تحلیل 2026-11-05 12:40:44 +03:30
amir 407596264f Standardize analysis docs and add user story features (#25)
Align docs/analysis files on one structure: metadata header, unnumbered
"مقدمه", numbered sections, and a final "نکات و پرسش‌های باز" section.

- user-story.md: add "نیازمندی‌های مرتبط" (FR refs) to each US, number
  the sections, and update the last-updated date
- requirements-specification.md: define "گزارش‌دهنده" and align the
  closing section name
- activity.md: add metadata header and مقدمه, drop English actor labels,
  give each diagram an AD-NN id, and add a status line
- CONTRIBUTING.md: record the analysis docs standard as section ۷
- features/: Gherkin scenarios for US-01, US-05 and US-15
2026-11-02 22:29:14 +03:30
11 changed files with 2306 additions and 153 deletions
+13
View File
@@ -110,4 +110,17 @@ classDiagram
---
## ۷. استاندارد مستندات تحلیل (`docs/analysis/`)
همه فایل‌های این پوشه باید ساختار یکسان داشته باشند:
- **سربرگ:** عنوان `#`، سپس `تهیه‌کننده`، `بازبین` و `آخرین به‌روزرسانی` (تاریخ شمسی با ارقام فارسی)، و بعد خط `---`.
- **بخش‌ها:** بخش «مقدمه» بدون شماره؛ بخش‌های اصلی با شماره (`## ۱.`)؛ آخرین بخش همیشه «نکات و پرسش‌های باز» است.
- **پایان:** خط `---` و سپس `**وضعیت سند:** ...`.
- **شناسه‌ها:** داستان‌ها `US-NN`، نیازمندی‌های کارکردی `FR-NN`، نیازمندی‌های غیرکارکردی `NFR-NN`، نمودارها `AD-NN`.
- **نام بازیگران:** فقط نام فارسی؛ دانشجو، استاد، کارمند تأسیسات، تعمیرکار، مدیر، کاربر سیستم. «گزارش‌دهنده» یعنی دانشجو یا استاد.
- **ارجاع:** هر داستان فیلد «نیازمندی‌های مرتبط» دارد و هر نمودار به داستان‌های خود ارجاع می‌دهد.
---
اگر مرحله‌ای را متوجه نشدید، تو گروه‌مون بپرسید تا سریع حلش کنیم.
+32 -20
View File
@@ -1,23 +1,31 @@
# نمودارهای فعالیت
# نمودارهای فعالیت (Activity Diagrams) – سامانه مدیریت و گزارش خرابی دانشگاهی
**تهیه‌کننده:** ارشیا همتی‌زاده
**بازبین:** رضا آدوسی
**آخرین به‌روزرسانی:** ۱۴۰۵/۰۸/۱۱
---
## مقدمه
این سند جریان‌های کاری اصلی سامانه گزارش و مدیریت خرابی‌های دانشگاه را با استفاده از Mermaid نمایش می‌دهد.
> **نکته:** نمودارها بر اساس بازیگران و ۱۷ داستان کاربری شناسایی‌شده در مستندات تحلیل تهیه شده‌اند. جزئیاتی که در نیازمندی‌ها صریحاً مشخص نشده‌اند، به‌عنوان فرض یا پرسش باز علامت‌گذاری شده‌اند و نباید قانون قطعی سیستم تلقی شوند.
> **نکته:** نمودارها بر اساس بازیگران و ۱۷ داستان کاربر شناسایی‌شده در [user-story.md](user-story.md) تهیه شده‌اند. جزئیاتی که در [نیازمندی‌ها](requirements-specification.md) صریحاً مشخص نشده‌اند، به‌عنوان فرض یا پرسش باز علامت‌گذاری شده‌اند و نباید قانون قطعی سیستم تلقی شوند.
## ۱. بازیگران و مسئولیت‌ها
| بازیگر | مسئولیت‌ها |
|---|---|
| دانشجو (Student) | ثبت و پیگیری گزارش خرابی، ارائه اطلاعات تکمیلی و تأیید یا رد نتیجه تعمیر |
| استاد (Professor) | ثبت و پیگیری گزارش خرابی، ارائه اطلاعات تکمیلی و تأیید یا رد نتیجه تعمیر |
| کارمند تأسیسات (Facilities Staff) | بررسی و فیلتر گزارش‌ها، تعیین اولویت، تخصیص تعمیرکار، به‌روزرسانی وضعیت و مشاهده تاریخچه |
| تعمیرکار (Technician) | مشاهده مأموریت‌های تخصیص‌یافته، شروع تعمیر، ثبت نتیجه و درخواست اطلاعات تکمیلی |
| مدیر (Manager) | مشاهده داشبورد مدیریتی؛ سطح دسترسی دقیق این نقش باید در نیازمندی‌ها مشخص شود |
| کاربر سیستم (System User) | عنوان عمومی کاربر احراز هویت‌شده در داستان‌های ورود و اعلان؛ لزوماً یک نقش انسانی مستقل نیست |
| دانشجو | ثبت و پیگیری گزارش خرابی، ارائه اطلاعات تکمیلی و تأیید یا رد نتیجه تعمیر |
| استاد | ثبت و پیگیری گزارش خرابی، ارائه اطلاعات تکمیلی و تأیید یا رد نتیجه تعمیر |
| کارمند تأسیسات | بررسی و فیلتر گزارش‌ها، تعیین اولویت، تخصیص تعمیرکار، به‌روزرسانی وضعیت و مشاهده تاریخچه |
| تعمیرکار | مشاهده مأموریت‌های تخصیص‌یافته، شروع تعمیر، ثبت نتیجه و درخواست اطلاعات تکمیلی |
| مدیر | مشاهده داشبورد مدیریتی؛ سطح دسترسی دقیق این نقش باید در نیازمندی‌ها مشخص شود |
| کاربر سیستم | عنوان عمومی کاربر احراز هویت‌شده در داستان‌های ورود و اعلان؛ لزوماً یک نقش انسانی مستقل نیست |
## ۲. نمودار فعالیت احراز هویت (Authentication Activity)
## ۲. نمودار فعالیت احراز هویت (AD-01)
**داستان کاربری مرتبط:** US-15 — ورود به سیستم (Log in).
**داستان کاربر مرتبط:** US-15 — ورود به سیستم.
این نمودار فرایند عمومی ورود کاربر را نشان می‌دهد. روش دقیق احراز هویت، بازیابی رمز عبور و سیاست قفل حساب در این بخش مشخص نشده‌اند.
@@ -35,9 +43,9 @@ flowchart TD
I --> J([پایان])
```
## ۳. نمودار فعالیت ثبت گزارش خرابی (Fault Reporting Activity)
## ۳. نمودار فعالیت ثبت گزارش خرابی (AD-02)
**داستان‌های کاربری مرتبط:**
**داستان‌های کاربر مرتبط:**
- US-01 — دانشجو گزارش خرابی ثبت می‌کند.
- US-02 — استاد گزارش خرابی ثبت می‌کند.
- US-03 — دانشجو یا استاد وضعیت گزارش را پیگیری می‌کند.
@@ -80,9 +88,9 @@ flowchart TD
**نکته مدل‌سازی:** حلقه اصلاح اطلاعات، اعتبارسنجی فرم را نمایش می‌دهد. باید مشخص شود آیا کاربر می‌تواند در هر زمان اطلاعات تکمیلی ارسال کند یا فقط پس از درخواست کارمند تأسیسات یا تعمیرکار مجاز به این کار است.
## ۴. نمودار فعالیت مدیریت گزارش‌ها (Report Management Activity)
## ۴. نمودار فعالیت مدیریت گزارش‌ها (AD-03)
**داستان‌های کاربری مرتبط:**
**داستان‌های کاربر مرتبط:**
- US-06 — مشاهده و فیلتر گزارش‌های باز.
- US-07 — تعیین اولویت گزارش.
- US-08 — تخصیص تعمیرکار.
@@ -131,9 +139,9 @@ flowchart TD
**نکته مدل‌سازی:** تصمیم «آیا گزارش آماده تخصیص است؟» یک مرحله پیشنهادی است. شرایط دقیق تخصیص تعمیرکار و نحوه بازگرداندن گزارش‌های ناقص به گزارش‌دهنده باید در نیازمندی‌ها مشخص شوند.
## ۵. نمودار فعالیت تعمیر خرابی (Repair Activity)
## ۵. نمودار فعالیت تعمیر خرابی (AD-04)
**داستان‌های کاربری مرتبط:**
**داستان‌های کاربر مرتبط:**
- US-11 — تعمیرکار کارهای تخصیص‌یافته را مشاهده می‌کند.
- US-12 — تعمیرکار تعمیر را آغاز می‌کند.
- US-13 — تعمیرکار نتیجه تعمیر را ثبت می‌کند.
@@ -178,9 +186,9 @@ flowchart TD
**نکته مدل‌سازی:** در این نمودار، درخواست اطلاعات تکمیلی باعث توقف موقت تعمیر می‌شود. باید مشخص شود چه کسی اطلاعات را ارائه می‌کند، پس از دریافت اطلاعات چگونه به تعمیرکار اطلاع داده می‌شود و آیا هنگام انتظار وضعیت گزارش تغییر می‌کند یا خیر.
## ۶. نمودار فعالیت تأیید تعمیر (Repair Verification Activity)
## ۶. نمودار فعالیت تأیید تعمیر (AD-05)
**داستان کاربری مرتبط:** US-05 — دانشجو یا استاد تکمیل تعمیر را تأیید یا رد می‌کند.
**داستان کاربر مرتبط:** US-05 — دانشجو یا استاد تکمیل تعمیر را تأیید یا رد می‌کند.
گزارش‌دهنده نتیجه ثبت‌شده تعمیر را بررسی می‌کند و مشخص می‌کند که آیا خرابی برطرف شده است یا خیر.
@@ -213,7 +221,7 @@ flowchart TD
**پرسش باز:** نیازمندی‌ها باید مشخص کنند پس از رد نتیجه تعمیر چه اتفاقی می‌افتد: آیا گزارش به کارمند تأسیسات بازمی‌گردد، دوباره به همان تعمیرکار تخصیص داده می‌شود یا فرایند دیگری اجرا می‌شود؟ این نمودار هیچ‌یک از این سیاست‌ها را به‌عنوان تصمیم قطعی انتخاب نمی‌کند.
## ۷. نمودار کلی چرخه عمر گزارش خرابی (Overall Fault Lifecycle)
## ۷. نمودار کلی چرخه عمر گزارش خرابی (AD-06)
این نمودار نمایی کلی از فرایند اصلی سیستم ارائه می‌دهد و مراحل ثبت گزارش، مدیریت، تعمیر و تأیید را به یکدیگر متصل می‌کند.
@@ -249,7 +257,7 @@ flowchart TD
**نکته مدل‌سازی:** بازگشت گزارش ردشده به مرحله بررسی کارمند تأسیسات، یک مسیر پیشنهادی برای پیگیری مجدد است و هنوز سیاست قطعی تخصیص مجدد محسوب نمی‌شود. این مسیر باید با اعضای تیم پروژه بررسی و تأیید شود.
## ۸. پرسش‌ها و ابهام‌های نیازمندی‌ها
## ۸. نکات و پرسش‌های باز
موارد زیر باید پیش از نهایی‌شدن نمودارها با اعضای تیم پروژه مشخص شوند:
@@ -263,3 +271,7 @@ flowchart TD
8. **اعلان‌ها:** کدام رویدادها باعث ارسال اعلان می‌شوند، دریافت‌کنندگان چه کسانی هستند و اعلان‌ها از چه کانالی ارسال می‌شوند؟
9. **دسترسی مدیر:** آیا دسترسی مدیر فقط به مشاهده داشبورد محدود است یا این نقش امکان مدیریت گزارش‌ها را نیز دارد؟
10. **احراز هویت:** آیا قوانین ورود یا کنترل دسترسی برای نقش‌های مختلف متفاوت است؟
---
**وضعیت سند:** نسخه اولیه (Draft) – آماده بازبینی
+297
View File
@@ -0,0 +1,297 @@
# نمودار کلاس (Class Diagram) – سامانه مدیریت و گزارش خرابی دانشگاهی
**تهیه‌کننده:** ارشیا همتی‌زاده
**بازبین:** امیرحسن عارف اصل
**آخرین به‌روزرسانی:** ۱۴۰۵/۰۸/۱۴
---
## مقدمه
این سند نمودار کلاس سامانهٔ مدیریت و گزارش خرابی دانشگاهی را بر اساس مستندات موجود در مخزن ارائه می‌دهد.
> **نکته:** چون پروژه هنوز وارد فاز کدنویسی نشده است، این نمودار یک **مدل دامنه (Domain Model)** است و کلاس‌های فنی مانند Repository، Controller و جدول پایگاه‌داده را شامل نمی‌شود. برای مشاهدهٔ مدل دامنهٔ تفصیلی، به `domain-model.md` (در صورت وجود) مراجعه کنید.
## ۱. بازیگران و نقش‌ها در نمودار
| بازیگر | کلاس متناظر | مستند مرجع |
|---|---|---|
| کاربر سیستم | `User` | FR-01، FR-02، US-15، AD-01 |
| گزارش‌دهنده | `Reporter` (انتزاعی) | requirements §۲ |
| دانشجو | `Student` | US-01 تا US-05، AD-02 |
| استاد | `Professor` | US-02 تا US-05، AD-02 |
| کارمند تأسیسات | `FacilitiesStaff` | FR-06 تا FR-09، FR-11، FR-16، FR-17، US-06 تا US-10، US-17، AD-03 |
| تعمیرکار | `Technician` | FR-10 تا FR-13، US-11 تا US-14، AD-04 |
| مدیر | `Manager` | FR-17، US-17، AD-03 |
## ۲. نمودار کلاس
```mermaid
classDiagram
direction LR
class User["کاربر سیستم"] {
+String نام_کاربری
+String رمز_عبور_هش‌شده
+Boolean فعال
+ورود(نام_کاربری, رمز_عبور) Boolean
+خروج() void
+بررسی_دسترسی(عملیات) Boolean
}
class Reporter["گزارش‌دهنده"] {
<<abstract>>
+ثبت_گزارش(عنوان, توضیحات, محل, نوع_تجهیز) FaultReport
+افزودن_اطلاعات_تکمیلی(گزارش, محتوا) void
+مشاهده_گزارش‌های_خود() List
+مشاهده_تاریخچه(گزارش) List
+تأیید_تعمیر(گزارش) void
+رد_تعمیر(گزارش, دلیل) void
}
class Student["دانشجو"]
class Professor["استاد"]
class FacilitiesStaff["کارمند تأسیسات"] {
+بررسی_گزارش‌ها(فیلتر) List
+تعیین_اولویت(گزارش, اولویت) void
+تخصیص_تعمیرکار(گزارش, تعمیرکار) Assignment
+تغییر_وضعیت(گزارش, وضعیت) void
+مشاهده_تاریخچه(گزارش) List
+مشاهده_داشبورد() Dashboard
}
class Technician["تعمیرکار"] {
+مشاهده_مأموریت‌ها() List
+شروع_تعمیر(گزارش) void
+ثبت_نتیجه_تعمیر(گزارش, توضیحات) RepairResult
+درخواست_اطلاعات(گزارش, توضیحات) InfoRequest
}
class Manager["مدیر"] {
+مشاهده_داشبورد_مدیریتی() Dashboard
}
class FaultReport["گزارش خرابی"] {
+String شناسه
+String عنوان
+String توضیحات
+ReportStatus وضعیت
+Priority اولویت
+DateTime تاریخ_ثبت
+اعتبارسنجی() Boolean
+تغییر_وضعیت(وضعیت_جدید) void
+بستن() void
+افزودن_رویداد(اقدام, انجام‌دهنده) void
}
class Location["محل خرابی"] {
+String ساختمان
+String طبقه
+String اتاق
}
class ReportStatus["وضعیت گزارش"] {
<<enumeration>>
ثبت‌شده
ارجاع‌شده
در_حال_تعمیر
تعمیر_انجام‌شده
بسته‌شده
}
class Priority["اولویت"] {
<<enumeration>>
کم
متوسط
زیاد
فوری
}
class EquipmentType["نوع تجهیز"] {
<<enumeration>>
روشنایی
تهویه
آسانسور
برق
پروژکتور
سایر
}
class Assignment["تخصیص تعمیرکار"] {
+DateTime تاریخ_تخصیص
+String وضعیت
}
class RepairResult["نتیجه تعمیر"] {
+String توضیحات
+DateTime تاریخ_ثبت
}
class ReporterFeedback["بازخورد گزارش‌دهنده"] {
+Boolean تأیید_شده
+String دلیل_رد
+DateTime تاریخ
+اعتبارسنجی_دلیل() Boolean
}
class SupplementaryInfo["اطلاعات تکمیلی"] {
+String نوع
+String محتوا
+DateTime تاریخ
}
class InfoRequest["درخواست اطلاعات تکمیلی"] {
+String توضیحات
+DateTime تاریخ
+Boolean پاسخ_داده_شده
}
class ReportHistoryEntry["رویداد تاریخچه"] {
+String اقدام
+String توضیحات
+DateTime تاریخ
}
class Notification["اعلان"] {
+String رویداد
+String کانال
+DateTime تاریخ
+Boolean خوانده_شده
}
class Dashboard["داشبورد مدیریتی"] {
+int تعداد_کل_گزارش‌ها
+int تعداد_گزارش‌های_باز
+int تعداد_درخواست‌های_فوری
+محاسبه_آمار() void
}
class AuthService["سرویس احراز هویت"] {
<<service>>
+اعتبارسنجی(نام_کاربری, رمز_عبور) Boolean
}
User <|-- Reporter
Reporter <|-- Student
Reporter <|-- Professor
User <|-- FacilitiesStaff
User <|-- Technician
User <|-- Manager
Reporter "1" --> "*" FaultReport : ثبت_می‌کند
FaultReport "*" --> "1" Location : در_محل
FaultReport "*" --> "1" EquipmentType : نوع_تجهیز
FaultReport "1" --> "1" ReportStatus : وضعیت
FaultReport "1" --> "0..1" Priority : اولویت
FaultReport "1" *-- "*" SupplementaryInfo : اطلاعات_تکمیلی
SupplementaryInfo "*" --> "1" Reporter : ارائه‌دهنده
InfoRequest "1" --> "0..1" SupplementaryInfo : پاسخ
FaultReport "1" *-- "*" InfoRequest : درخواست‌ها
InfoRequest "*" --> "1" User : درخواست‌دهنده
FaultReport "1" *-- "*" Assignment : تخصیص‌ها
Assignment "*" --> "1" Technician : تعمیرکار
Assignment "*" --> "1" FacilitiesStaff : تخصیص‌دهنده
FaultReport "1" *-- "*" RepairResult : نتایج_تعمیر
RepairResult "*" --> "1" Technician : ثبت‌کننده
FaultReport "1" *-- "*" ReporterFeedback : بازخوردها
ReporterFeedback "*" --> "1" Reporter : تأییدکننده
ReporterFeedback "*" --> "0..1" RepairResult : درباره_نتیجه
FaultReport "1" *-- "*" ReportHistoryEntry : تاریخچه
ReportHistoryEntry "*" --> "1" User : انجام‌دهنده
Notification "*" --> "1" User : گیرنده
Notification "*" --> "1" FaultReport : مربوط_به
FacilitiesStaff ..> Dashboard : مشاهده
Manager ..> Dashboard : مشاهده
Dashboard ..> FaultReport : محاسبه_از
User ..> AuthService : احراز_هویت
note for Manager "طبق FR-17 و US-17 فقط «مشاهده داشبورد» برای مدیر ذکر شده؛ سطح دسترسی کامل او پرسش باز ۹ در activity.md است."
note for Priority "سطوح رسمی اولویت در نیازمندی‌ها تعیین نشده (پرسش باز ۳). این مقادیر موقت‌اند."
note for ReportStatus "فهرست رسمی وضعیت‌ها و انتقال‌های مجاز تعیین نشده (پرسش باز ۴). «باز» در FR-17 و US-06 به‌معنای گزارش بسته‌نشده است، نه یک وضعیت رسمی."
note for Assignment "پرسش باز ۵: آیا یک گزارش هم‌زمان به یک تعمیرکار تخصیص می‌یابد یا چند تعمیرکار؟"
note for InfoRequest "پرسش باز ۶: چه کسانی مجاز به درخواست اطلاعات و پاسخ به آن هستند؟"
note for ReporterFeedback "دلیل رد اجباری است (US-05.feature). تأیید فقط توسط گزارش‌دهنده همان گزارش و فقط در وضعیت «تعمیر انجام‌شده» مجاز است."
note for FaultReport "عنوان حداکثر ۱۵۰ کاراکتر؛ فیلدهای اجباری: عنوان، توضیحات، محل خرابی، نوع تجهیز (US-01.feature). وضعیت اولیه: ثبت‌شده."
note for AuthService "از سناریوی «سرویس احراز هویت در دسترس نیست» در US-15.feature. روش احراز هویت و بازیابی رمز در مستندات مشخص نشده."
```
## ۳. جدول ردیابی (Traceability)
| عنصر نمودار | نوع | مستند مرجع |
|---|---|---|
| `User` / کاربر سیستم | کلاس | FR-01، FR-02، US-15، AD-01؛ activity §۱ |
| `Reporter` / گزارش‌دهنده | کلاس انتزاعی | requirements §۲ («گزارش‌دهنده = دانشجو یا استاد»)، US-01 تا US-05، AD-02، AD-05 |
| `Student` / دانشجو | کلاس | US-01، US-03، US-04، US-05، AD-02 |
| `Professor` / استاد | کلاس | US-02، US-03، US-04، US-05، AD-02 |
| `FacilitiesStaff` / کارمند تأسیسات | کلاس | FR-06 تا FR-09، FR-11، FR-16، FR-17، US-06 تا US-10، US-17، AD-03 |
| `Technician` / تعمیرکار | کلاس | FR-10 تا FR-13، US-11 تا US-14، AD-04 |
| `Manager` / مدیر | کلاس | FR-17، US-17، AD-03؛ activity §۱ |
| `FaultReport` / گزارش خرابی | کلاس | FR-03 تا FR-05، FR-11، FR-14 تا FR-16، US-01 تا US-05، US-09، US-10، AD-02 تا AD-06 |
| `ReportStatus` / وضعیت گزارش | enum | US-01 (`ثبت‌شده`)، US-05 (`ارجاع‌شده`، `در حال تعمیر`، `تعمیر انجام‌شده`، `بسته‌شده`)، US-12، AD-03 تا AD-05 |
| `Priority` / اولویت | enum موقت | FR-07، US-07، AD-03؛ سطوح دقیق: پرسش باز ۳ |
| `Location` / محل خرابی | کلاس | FR-03، US-01؛ دامنه فضاها: ابهام README |
| `EquipmentType` / نوع تجهیز | enum | FR-03، US-01؛ مثال‌های README: روشنایی، تهویه، آسانسور، برق، پروژکتور |
| `Assignment` / تخصیص تعمیرکار | کلاس | FR-09، US-08، US-11، AD-03، AD-04 |
| `RepairResult` / نتیجه تعمیر | کلاس | FR-12، US-13، AD-04 |
| `ReporterFeedback` / بازخورد گزارش‌دهنده | کلاس | FR-14، US-05، AD-05، US-05.feature |
| `SupplementaryInfo` / اطلاعات تکمیلی | کلاس | FR-04، US-04، US-14، AD-02، AD-04 |
| `InfoRequest` / درخواست اطلاعات | کلاس | FR-13، US-14، AD-04 |
| `ReportHistoryEntry` / تاریخچه | کلاس | FR-16، US-03، US-05، US-10، AD-03 |
| `Notification` / اعلان | کلاس | FR-15، US-16، AD-04 |
| `Dashboard` / داشبورد | کلاس (Read Model) | FR-17، US-17، AD-03 |
| `AuthService` / سرویس احراز هویت | سرویس خارجی | US-15.feature: «سرویس احراز هویت در دسترس نیست» |
## ۴. محدودیت‌های اعمال‌شده از فایل‌های Feature
| محدودیت | منبع | محل بازتاب در نمودار |
|---|---|---|
| عنوان حداکثر ۱۵۰ کاراکتر | US-01.feature | `note for FaultReport` |
| عنوان، توضیحات، محل، نوع تجهیز اجباری‌اند | US-01.feature | `FaultReport.اعتبارسنجی()` + note |
| وضعیت اولیه «ثبت‌شده» | US-01.feature | `ReportStatus` + note |
| دلیل رد بازخورد اجباری است | US-05.feature | `ReporterFeedback.دلیل_رد` + `اعتبارسنجی_دلیل()` |
| تأیید فقط توسط گزارش‌دهنده همان گزارش | US-05.feature | رابطه `ReporterFeedback --> Reporter` + note |
| تأیید فقط در وضعیت «تعمیر انجام‌شده» | US-05.feature | `note for ReporterFeedback` |
| تأیید دوباره نباید وضعیت را دوباره تغییر دهد (Idempotent) | US-05.feature | `note for ReporterFeedback` |
| کنترل دسترسی مبتنی بر نقش و جلوگیری از دسترسی مستقیم به صفحات نقش دیگر | US-15.feature | `User.بررسی_دسترسی()` + ارث‌بری نقش‌ها |
| پیام خطای ورود نباید مشخص کند کدام فیلد اشتباه است | US-15.feature | `User.ورود()` + `note for AuthService` |
## ۵. نکات و پرسش‌های باز
موارد زیر در مستندات به‌عنوان پرسش باز علامت‌گذاری شده‌اند و در نمودار فقط به‌صورت `note` آمده‌اند، نه به‌عنوان قانون قطعی:
1. **فهرست رسمی وضعیت‌ها و انتقال‌های مجاز** — پرسش باز ۴ در [`activity.md`](activity.md).
2. **سطوح و معیارهای اولویت** — پرسش باز ۳ در [`activity.md`](activity.md).
3. **یک یا چند تعمیرکار برای هر گزارش** — پرسش باز ۵ در [`activity.md`](activity.md).
4. **چه کسانی می‌توانند درخواست اطلاعات بدهند یا پاسخ دهند** — پرسش باز ۶ در [`activity.md`](activity.md).
5. **جریان دقیق پس از رد تعمیر توسط گزارش‌دهنده** — پرسش باز ۷ در [`activity.md`](activity.md).
6. **کانال اعلان‌ها: داخل سامانه، پیامک یا ایمیل** — پرسش باز ۸ در [`activity.md`](activity.md) و بخش پرسش‌های باز [`requirements-specification.md`](requirements-specification.md).
7. **سطح دسترسی دقیق مدیر** — پرسش باز ۹ در [`activity.md`](activity.md).
8. **دامنه فضاها: آموزشی/عمومی یا شامل خوابگاه و اداری** — ابهام باقی‌مانده در [`README.md`](../../README.md).
9. **آیا یک کاربر می‌تواند چند نقش داشته باشد؟** — در مستندات صریحاً مشخص نشده است. اگر پاسخ «بله» باشد، ارث‌بری `User` به نقش‌ها باید به **ترکیب (Composition)** با کلاس `نقش` تغییر کند.
10. **روش احراز هویت و بازیابی رمز عبور** — در [`activity.md`](activity.md) §۲ به‌عنوان نامشخص علامت‌گذاری شده است.
## ۶. مواردی که عمداً مدل نشده‌اند
موارد زیر در مستندات تحلیل تعریف نشده‌اند و آگاهانه از نمودار حذف شده‌اند:
- **Repository، Controller، Database، API** — مربوط به فاز طراحی فنی هستند.
- **سرویس ذخیره‌سازی** (US-01.feature) — فقط یک سناریوی خطاست، نه یک مؤلفهٔ معماری تعریف‌شده.
- **«باز» به‌عنوان وضعیت** — در FR-17 و US-06 به‌معنای گزارش بسته‌نشده است؛ وضعیت رسمی نیست.
- **«نیازمند پیگیری» به‌عنوان وضعیت** — در US-05 به‌صورت «علامت‌گذاری برای پیگیری بیشتر» آمده، نه وضعیت رسمی.
## ۷. پیشنهاد اصلاح استاندارد
استاندارد فعلی [`CONTRIBUTING.md`](../../CONTRIBUTING.md) §۷ شناسهٔ `AD-NN` را برای Activity Diagram تعریف کرده است اما شناسه‌ای برای Class Diagram ندارد. پیشنهاد می‌شود شناسهٔ `CD-NN` (مثلاً `CD-01` برای همین سند) به استاندارد اضافه شود تا ارجاع‌دهی یکدست بماند.
---
**وضعیت سند:** نسخه اولیه (Draft) – آماده بازبینی
+823
View File
@@ -0,0 +1,823 @@
# مدل داده (Data Model) – سامانه مدیریت و گزارش خرابی دانشگاهی
**تهیه‌کننده:** ارشیا همتی‌زاده
**بازبین:** رضا آدوسی
**آخرین به‌روزرسانی:** ۱۴۰۵/۰۸/۱۴
---
## مقدمه
این سند مدل دادهٔ منطقی سامانهٔ مدیریت و گزارش خرابی دانشگاهی را بر اساس مستندات تحلیل موجود ارائه می‌دهد. هدف، تعریف ساختار ذخیره‌سازی مفاهیم دامنه، کلیدها، محدودیت‌ها و روابط بین آن‌ها است؛ به‌گونه‌ای که پیاده‌سازی هر DBMS رابطه‌ای (PostgreSQL، MySQL، SQL Server و ...) از آن ممکن باشد.
> **نکتهٔ مهم:** مدل داده با مدل دامنه یکی نیست. مدل داده به «چگونه ذخیره کنیم» پاسخ می‌دهد و مدل دامنه به «چه قواعدی در کسب‌وکار حاکم است». برخی ساده‌سازی‌های عمدی در این سند (مثل ادغام دانشجو و استاد در یک جدول) در بخش «تصمیم‌های مدل‌سازی» توضیح داده شده‌اند.
**قرارداد نام‌گذاری:** نام جدول‌ها و ستون‌ها به انگلیسی و `snake_case` است (استاندارد فنی پایگاه‌داده). برچسب‌های فارسی در جداول مرجع (`label_fa`) نگهداری می‌شوند تا تغییر متن فارسی نیازی به مهاجرت داده نداشته باشد. این تصمیم با بند «نام بازیگران: فقط نام فارسی» در `CONTRIBUTING.md` §۷ تعارضی ندارد، زیرا آن بند دربارهٔ **متن مستندات** است، نه نام‌گذاری فنی.
## ۱. تصمیم‌های مدل‌سازی
| # | تصمیم | گزینهٔ جایگزین | دلیل انتخاب | وابسته به |
|---|---|---|---|---|
| D1 | دانشجو و استاد در یک جدول `users` با ستون `role_code` | دو جدول جدا یا ارث‌بری جدولی | در همهٔ مستندات، دانشجو و استاد رفتار دادهٔ یکسانی دارند و فقط نقششان متفاوت است | — |
| D2 | `location_text` به‌صورت متن آزاد | جدول `locations` با ساختمان/طبقه/اتاق | `US-01.feature` محل را به‌صورت **یک فیلد متنی** با مقدار «ساختمان الف - کلاس ۱۰۲» تعریف کرده است | ابهام دامنه در `README.md` |
| D3 | وضعیت و اولویت و نوع تجهیز و نقش به‌صورت **جدول مرجع** | `ENUM` پایگاه‌داده یا `CHECK` | فهرست وضعیت‌ها و اولویت‌ها در پرسش‌های باز ۳ و ۴ تعریف‌نشده‌اند و باید بدون مهاجرت schema قابل تغییر باشند | پرسش باز ۳ و ۴ |
| D4 | یک گزارش می‌تواند **چند نتیجهٔ تعمیر** داشته باشد | یک نتیجهٔ واحد | `AD-06` مسیر بازگشت پس از رد را نشان می‌دهد؛ اگر این مسیر تأیید شود، چرخهٔ تعمیر تکرار می‌شود | پرسش باز ۷ |
| D5 | تأیید/رد به‌صورت جدول `report_feedbacks` با `UNIQUE (report_id, repair_result_id)` | فقط یک ردیف بازخورد per report | محدودیت یکتا، کلیک دوباره روی «تأیید» را در سطح داده بی‌اثر می‌کند (الزام `US-05.feature`) | — |
| D6 | حذف فیزیکی گزارش ممنوع؛ آرشیو = وضعیت `CLOSED` | ستون `deleted_at` | `NFR-05` از حذف ناخواسته منع می‌کند و بستن گزارش همان نقش آرشیو را دارد | نیاز به حذف منطقی: پرسش باز ۱۲ |
| D7 | `version` برای قفل خوش‌بینانه روی `fault_reports` و `users` | قفل بدبینانه | جلوگیری از بازنویسی هم‌زمان تغییرات (مرتبط با الزام idempotent در `US-05.feature`) | — |
| D8 | `report_no` جدا از `id` | استفاده از `id` به‌عنوان شناسه نمایشی | `US-05.feature` از قالب `R-100` استفاده می‌کند و `US-01.feature` «شناسه یکتا» را نمایش می‌دهد | فرمت تولید: پرسش باز ۱۱ |
## ۲. فهرست جدول‌ها
| # | جدول | نوع | توضیح | Aggregate |
|---|---|---|---|---|
| ۱ | `roles` | مرجع | نقش‌های کاربری | — |
| ۲ | `report_statuses` | مرجع | وضعیت‌های گزارش | — |
| ۳ | `priorities` | مرجع | سطوح اولویت | — |
| ۴ | `equipment_types` | مرجع | انواع تجهیز | — |
| ۵ | `notification_channels` | مرجع | کانال‌های اعلان | — |
| ۶ | `users` | اصلی | کاربران سامانه | کاربر |
| ۷ | `fault_reports` | اصلی | گزارش‌های خرابی | گزارش خرابی |
| ۸ | `report_supplementary_info` | اصلی | اطلاعات تکمیلی گزارش | گزارش خرابی |
| ۹ | `report_info_requests` | اصلی | درخواست‌های اطلاعات تکمیلی | گزارش خرابی |
| ۱۰ | `report_assignments` | اصلی | تخصیص تعمیرکار | گزارش خرابی |
| ۱۱ | `repair_results` | اصلی | نتایج تعمیر | گزارش خرابی |
| ۱۲ | `report_feedbacks` | اصلی | تأیید/رد گزارش‌دهنده | گزارش خرابی |
| ۱۳ | `report_history` | اصلی | تاریخچهٔ اقدامات (append-only) | گزارش خرابی |
| ۱۴ | `notifications` | اصلی | اعلان‌ها | اعلان |
| ۱۵ | `report_status_transitions` | اختیاری | انتقال‌های مجاز وضعیت | — |
> **داشبورد** جدول ندارد؛ یک `VIEW` یا کوئری تجمیعی روی `fault_reports` است (طبق `class-diagram.md` که آن را `Read Model` علامت زده است).
## ۳. نمودار ERD
> نمودار به‌صورت انگلیسی نوشته شده تا در همهٔ رندررها (از جمله GitHub) درست نمایش داده شود. توضیحات فارسی در بخش‌های ۴ و ۵ آمده است.
```mermaid
erDiagram
ROLES ||--o{ USERS : "assigned to"
USERS ||--o{ FAULT_REPORTS : "registers"
REPORT_STATUSES ||--o{ FAULT_REPORTS : "has"
PRIORITIES |o--o{ FAULT_REPORTS : "has"
EQUIPMENT_TYPES ||--o{ FAULT_REPORTS : "classifies"
FAULT_REPORTS ||--o{ REPORT_SUPPLEMENTARY_INFO : "contains"
USERS ||--o{ REPORT_SUPPLEMENTARY_INFO : "provides"
FAULT_REPORTS ||--o{ REPORT_INFO_REQUESTS : "contains"
USERS ||--o{ REPORT_INFO_REQUESTS : "requests"
REPORT_SUPPLEMENTARY_INFO |o--o| REPORT_INFO_REQUESTS : "answers"
FAULT_REPORTS ||--o{ REPORT_ASSIGNMENTS : "contains"
USERS ||--o{ REPORT_ASSIGNMENTS : "is technician"
USERS ||--o{ REPORT_ASSIGNMENTS : "is assigner"
FAULT_REPORTS ||--o{ REPAIR_RESULTS : "contains"
USERS ||--o{ REPAIR_RESULTS : "records"
FAULT_REPORTS ||--o{ REPORT_FEEDBACKS : "contains"
REPAIR_RESULTS ||--o{ REPORT_FEEDBACKS : "about"
USERS ||--o{ REPORT_FEEDBACKS : "gives"
FAULT_REPORTS ||--o{ REPORT_HISTORY : "logs"
USERS ||--o{ REPORT_HISTORY : "acts"
USERS ||--o{ NOTIFICATIONS : "receives"
FAULT_REPORTS ||--o{ NOTIFICATIONS : "concerns"
NOTIFICATION_CHANNELS ||--o{ NOTIFICATIONS : "via"
ROLES {
varchar code PK
varchar label_fa
smallint sort_order
boolean is_active
}
REPORT_STATUSES {
varchar code PK
varchar label_fa
smallint sort_order
boolean is_active
}
PRIORITIES {
varchar code PK
varchar label_fa
smallint sort_order
boolean is_active
}
EQUIPMENT_TYPES {
varchar code PK
varchar label_fa
smallint sort_order
boolean is_active
}
NOTIFICATION_CHANNELS {
varchar code PK
varchar label_fa
boolean is_active
}
USERS {
bigserial id PK
varchar username UK
varchar password_hash
varchar role_code FK
varchar display_name
boolean is_active
timestamptz created_at
timestamptz updated_at
integer version
}
FAULT_REPORTS {
bigserial id PK
varchar report_no UK
varchar title
text description
varchar location_text
varchar equipment_type_code FK
varchar status_code FK
varchar priority_code FK
bigint reporter_id FK
timestamptz created_at
timestamptz updated_at
timestamptz closed_at
integer version
}
REPORT_SUPPLEMENTARY_INFO {
bigserial id PK
bigint report_id FK
varchar info_type
text content_text
varchar attachment_ref
bigint provided_by_id FK
timestamptz created_at
}
REPORT_INFO_REQUESTS {
bigserial id PK
bigint report_id FK
bigint requested_by_id FK
text description
timestamptz requested_at
timestamptz responded_at
bigint response_info_id FK
}
REPORT_ASSIGNMENTS {
bigserial id PK
bigint report_id FK
bigint technician_id FK
bigint assigned_by_id FK
timestamptz assigned_at
varchar status
}
REPAIR_RESULTS {
bigserial id PK
bigint report_id FK
bigint technician_id FK
text description
timestamptz recorded_at
}
REPORT_FEEDBACKS {
bigserial id PK
bigint report_id FK
bigint repair_result_id FK
bigint reporter_id FK
boolean is_approved
text rejection_reason
timestamptz created_at
}
REPORT_HISTORY {
bigserial id PK
bigint report_id FK
varchar action_code
bigint actor_id FK
jsonb details
timestamptz occurred_at
}
NOTIFICATIONS {
bigserial id PK
bigint recipient_id FK
bigint report_id FK
varchar event_code
varchar channel_code FK
boolean is_read
timestamptz created_at
timestamptz read_at
}
```
## ۴. جداول مرجع (Lookup)
همهٔ جداول مرجع ساختار یکسانی دارند: `code` (کلید پایدار انگلیسی)، `label_fa` (برچسب فارسی)، `sort_order` و `is_active`. تغییر متن فارسی بدون مهاجرت schema ممکن است و افزودن مقدار جدید نیاز به تغییر کد ندارد.
### ۴.۱. `roles` — نقش‌ها
| code | label_fa | sort_order | مرجع |
|---|---|---|---|
| `STUDENT` | دانشجو | ۱۰ | requirements §۲ |
| `PROFESSOR` | استاد | ۲۰ | requirements §۲ |
| `FACILITIES_STAFF` | کارمند تأسیسات | ۳۰ | requirements §۲ |
| `TECHNICIAN` | تعمیرکار | ۴۰ | requirements §۲ |
| `MANAGER` | مدیر | ۵۰ | requirements §۲ |
> **نکته:** «کاربر سیستم» در `AD-01` و `US-15` یک **نقش** نیست، بلکه عنوان عمومی هر کاربر احراز هویت‌شده است (طبق `activity.md` §۱). بنابراین در این جدول مقدار ندارد.
### ۴.۲. `report_statuses` — وضعیت‌های گزارش
| code | label_fa | sort_order | مستند مرجع |
|---|---|---|---|
| `SUBMITTED` | ثبت‌شده | ۱۰ | `US-01.feature`، `US-05.feature` |
| `ASSIGNED` | ارجاع‌شده | ۲۰ | `US-05.feature` |
| `IN_REPAIR` | در حال تعمیر | ۳۰ | `US-05.feature`، `US-12` |
| `REPAIRED` | تعمیر انجام‌شده | ۴۰ | `US-05.feature` |
| `CLOSED` | بسته‌شده | ۵۰ | `US-05.feature` |
> ⚠️ **پرسش باز ۴:** این فهرست از مثال‌های `US-05.feature` استخراج شده و **رسمی نیست**. «باز» (در `FR-17` و `US-06`) یک وضعیت نیست؛ به‌معنای «هر گزارشی که `status_code <> 'CLOSED'` است» می‌باشد و نباید ردیفی در این جدول داشته باشد. «نیازمند پیگیری» نیز فعلاً برچسب است، نه وضعیت (پرسش باز ۷).
### ۴.۳. `priorities` — سطوح اولویت
| code | label_fa | sort_order | مستند مرجع |
|---|---|---|---|
| `LOW` | کم | ۱۰ | **فرض موقت** |
| `MEDIUM` | متوسط | ۲۰ | **فرض موقت** |
| `HIGH` | زیاد | ۳۰ | **فرض موقت** |
| `URGENT` | فوری | ۴۰ | `US-17` (واژهٔ «فوری» آمده) |
> ⚠️ **پرسش باز ۳:** سطوح رسمی و معیار هر سطح در نیازمندی‌ها تعیین نشده است. سه سطح اول **فرض موقت** هستند و باید پیش از پیاده‌سازی تأیید شوند.
### ۴.۴. `equipment_types` — انواع تجهیز
| code | label_fa | مستند مرجع |
|---|---|---|
| `LIGHTING` | روشنایی | `US-01.feature` |
| `HVAC` | تهویه | `README.md` |
| `ELEVATOR` | آسانسور | `README.md` |
| `ELECTRICAL` | برق | `README.md` |
| `PROJECTOR` | پروژکتور | `README.md` |
| `OTHER` | سایر | پیشنهادی (پوشش موارد دیگر) |
### ۴.۵. `notification_channels` — کانال‌های اعلان
| code | label_fa | وضعیت |
|---|---|---|
| `IN_APP` | داخل سامانه | **تأییدنشده** |
| `SMS` | پیامک | **تأییدنشده** |
| `EMAIL` | ایمیل | **تأییدنشده** |
> ⚠️ **پرسش باز ۸:** هیچ کانالی در نیازمندی‌ها تأیید نشده است. این سه مقدار فقط به‌عنوان **دادهٔ نمونه** درج شده‌اند و باید پس از تصمیم‌گیری تیم نهایی شوند.
## ۵. جداول اصلی (Entities)
### ۵.۱. `users` — کاربران سامانه
| ستون | نوع | Null | پیش‌فرض | محدودیت | توضیح | مرجع |
|---|---|---|---|---|---|---|
| `id` | `bigserial` | خیر | — | PK | شناسه فنی | — |
| `username` | `varchar(50)` | خیر | — | UNIQUE، `CHECK (btrim(username) <> '')` | نام کاربری | `FR-01`، `US-15.feature` |
| `password_hash` | `varchar(255)` | خیر | — | — | هش رمز (هرگز رمز خام) | `FR-01`، `NFR-01` |
| `role_code` | `varchar(30)` | خیر | — | FK → `roles.code` | نقش کاربر | `FR-02` |
| `display_name` | `varchar(100)` | بله | NULL | — | نام نمایشی (در مستندات الزامی نشده) | — |
| `is_active` | `boolean` | خیر | `true` | — | فعال/غیرفعال | — |
| `created_at` | `timestamptz` | خیر | `now()` | — | زمان ایجاد | — |
| `updated_at` | `timestamptz` | خیر | `now()` | — | آخرین تغییر | — |
| `version` | `integer` | خیر | `1` | — | قفل خوش‌بینانه | — |
**نکته:** `US-15.feature` الزام می‌کند پیام خطای ورود مشخص نکند کدام فیلد اشتباه است. این یک قاعدهٔ **لایهٔ اپلیکیشن** است، نه محدودیت داده.
> ⚠️ **پرسش باز ۹ (مهم):** اگر تصمیم تیم این باشد که یک کاربر می‌تواند **چند نقش** داشته باشد، باید ستون `role_code` حذف و جدول `user_roles (user_id, role_code)` اضافه شود. مدل فعلی بر پایهٔ **یک نقش per کاربر** است و با `class-diagram.md` (که ارث‌بری دارد) هم‌خوان است، ولی با `domain-model.md` (که نقش را Value Object چندمقداری دیده) هم‌خوان نیست. **پس از پاسخ به پرسش باز ۹، هر سه سند باید هم‌زمان به‌روزرسانی شوند.**
### ۵.۲. `fault_reports` — گزارش‌های خرابی
| ستون | نوع | Null | پیش‌فرض | محدودیت | توضیح | مرجع |
|---|---|---|---|---|---|---|
| `id` | `bigserial` | خیر | — | PK | شناسه فنی | — |
| `report_no` | `varchar(20)` | خیر | — | UNIQUE | شناسهٔ نمایشی (مثل `R-100`) | `US-05.feature` |
| `title` | `varchar(150)` | خیر | — | `CHECK (char_length(title) BETWEEN 1 AND 150)` | عنوان | `US-01.feature`، `FR-03` |
| `description` | `text` | خیر | — | `CHECK (btrim(description) <> '')` | توضیحات | `US-01.feature`، `FR-03` |
| `location_text` | `varchar(255)` | خیر | — | `CHECK (btrim(location_text) <> '')` | محل خرابی (متن آزاد) | `US-01.feature`، `FR-03` |
| `equipment_type_code` | `varchar(30)` | خیر | — | FK → `equipment_types.code` | نوع تجهیز | `US-01.feature`، `FR-03` |
| `status_code` | `varchar(30)` | خیر | `'SUBMITTED'` | FK → `report_statuses.code` | وضعیت جاری | `US-01.feature` |
| `priority_code` | `varchar(30)` | بله | NULL | FK → `priorities.code` | اولویت (تا زمان تعیین خالی است) | `FR-07`، `US-07` |
| `reporter_id` | `bigint` | خیر | — | FK → `users.id` | گزارش‌دهنده | `FR-03`، `US-01`، `US-02` |
| `created_at` | `timestamptz` | خیر | `now()` | — | زمان ثبت | — |
| `updated_at` | `timestamptz` | خیر | `now()` | — | آخرین تغییر | — |
| `closed_at` | `timestamptz` | بله | NULL | — | زمان بستن گزارش | `US-05.feature` |
| `version` | `integer` | خیر | `1` | — | قفل خوش‌بینانه | `US-05.feature` (idempotency) |
**محدودیت ترکیبی:** `UNIQUE (id, reporter_id)` — برای اینکه جدول بازخورد بتواند تضمین کند فقط گزارش‌دهندهٔ همان گزارش تأیید می‌کند (بخش ۶).
> **نکتهٔ D2:** `location_text` عمداً متن آزاد است چون `US-01.feature` محل را به‌صورت یک فیلد متنی تعریف کرده است. اگر دامنهٔ سامانه گسترش یابد (ابهام `README.md` دربارهٔ خوابگاه و فضاهای اداری)، در آینده می‌توان `location_text` را نگه داشت و جدول ساختاریافتهٔ `locations` را به‌عنوان مکمل اضافه کرد. `class-diagram.md` فعلاً نسخهٔ ساختاریافته را نشان می‌دهد و این تفاوت باید در بازبینی هم‌راستا شود.
> **نکتهٔ D6:** حذف فیزیکی ردیف مجاز نیست (`NFR-05`). بستن گزارش با `status_code = 'CLOSED'` و مقدارگرفتن `closed_at` انجام می‌شود.
### ۵.۳. `report_supplementary_info` — اطلاعات تکمیلی
| ستون | نوع | Null | پیش‌فرض | محدودیت | توضیح | مرجع |
|---|---|---|---|---|---|---|
| `id` | `bigserial` | خیر | — | PK | — | — |
| `report_id` | `bigint` | خیر | — | FK → `fault_reports.id` | گزارش مرتبط | `FR-04`، `US-04` |
| `info_type` | `varchar(20)` | خیر | — | `CHECK (info_type IN ('TEXT','IMAGE'))` | نوع محتوا | `FR-04` |
| `content_text` | `text` | بله | NULL | `CHECK (info_type <> 'TEXT' OR content_text IS NOT NULL)` | متن توضیح | `FR-04` |
| `attachment_ref` | `varchar(500)` | بله | NULL | `CHECK (info_type <> 'IMAGE' OR attachment_ref IS NOT NULL)` | مسیر/شناسهٔ فایل تصویر | `FR-04` |
| `provided_by_id` | `bigint` | خیر | — | FK → `users.id` | ارائه‌دهنده | `US-04` |
| `created_at` | `timestamptz` | خیر | `now()` | — | زمان ارائه | — |
> **پرسش باز ۶:** `US-04` فقط گزارش‌دهنده را ارائه‌دهنده می‌داند، اما `AD-04` نشان می‌دهد تعمیرکار نیز می‌تواند درخواست اطلاعات دهد. اینکه چه کسی **مجاز به ارائه** است در مستندات صریح نیست؛ مدل فعلی هر کاربری را می‌پذیرد و کنترل آن به لایهٔ اپلیکیشن واگذار شده است.
### ۵.۴. `report_info_requests` — درخواست اطلاعات تکمیلی
| ستون | نوع | Null | پیش‌فرض | محدودیت | توضیح | مرجع |
|---|---|---|---|---|---|---|
| `id` | `bigserial` | خیر | — | PK | — | — |
| `report_id` | `bigint` | خیر | — | FK → `fault_reports.id` | گزارش مرتبط | `FR-13`، `US-14` |
| `requested_by_id` | `bigint` | خیر | — | FK → `users.id` | درخواست‌دهنده | `US-14`، `AD-04` |
| `description` | `text` | خیر | — | `CHECK (btrim(description) <> '')` | متن درخواست | `US-14` |
| `requested_at` | `timestamptz` | خیر | `now()` | — | زمان درخواست | — |
| `responded_at` | `timestamptz` | بله | NULL | — | زمان پاسخ | `AD-04` |
| `response_info_id` | `bigint` | بله | NULL | FK → `report_supplementary_info.id`، UNIQUE | پاسخ مرتبط | `AD-04` |
> **پرسش باز ۶:** اینکه چه کسانی مجاز به **درخواست** هستند (فقط تعمیرکار یا کارمند تأسیسات هم) در مستندات مشخص نیست. ستون `requested_by_id` به `users` ارجاع می‌دهد و نقش در `report_history` ثبت می‌شود.
### ۵.۵. `report_assignments` — تخصیص تعمیرکار (مأموریت)
| ستون | نوع | Null | پیش‌فرض | محدودیت | توضیح | مرجع |
|---|---|---|---|---|---|---|
| `id` | `bigserial` | خیر | — | PK | — | — |
| `report_id` | `bigint` | خیر | — | FK → `fault_reports.id` | گزارش | `FR-09`، `US-08` |
| `technician_id` | `bigint` | خیر | — | FK → `users.id` | تعمیرکار | `US-08`، `US-11` |
| `assigned_by_id` | `bigint` | خیر | — | FK → `users.id` | تخصیص‌دهنده (کارمند تأسیسات) | `AD-03` |
| `assigned_at` | `timestamptz` | خیر | `now()` | — | زمان تخصیص | — |
| `status` | `varchar(20)` | خیر | `'ASSIGNED'` | `CHECK (status IN ('ASSIGNED','STARTED','DONE','CANCELLED'))` | وضعیت تخصیص | `US-12`، `US-13` |
> ⚠️ **پرسش باز ۵:** آیا یک گزارش می‌تواند هم‌زمان چند تخصیص فعال داشته باشد؟ مدل فعلی این را **مجاز** می‌داند (چند ردیف per report). اگر تصمیم نهایی «یک تعمیرکار در هر لحظه» باشد، باید یک **ایندکس یگانهٔ جزئی** اضافه شود:
> `CREATE UNIQUE INDEX ... ON report_assignments (report_id) WHERE status IN ('ASSIGNED','STARTED');`
### ۵.۶. `repair_results` — نتایج تعمیر
| ستون | نوع | Null | پیش‌فرض | محدودیت | توضیح | مرجع |
|---|---|---|---|---|---|---|
| `id` | `bigserial` | خیر | — | PK | — | — |
| `report_id` | `bigint` | خیر | — | FK → `fault_reports.id` | گزارش | `FR-12`، `US-13` |
| `technician_id` | `bigint` | خیر | — | FK → `users.id` | ثبت‌کننده | `US-13` |
| `description` | `text` | خیر | — | `CHECK (btrim(description) <> '')` | توضیحات اقدامات | `FR-12` |
| `recorded_at` | `timestamptz` | خیر | `now()` | — | زمان ثبت | — |
> **نکتهٔ D4:** چند نتیجه per گزارش مجاز است تا اگر مسیر «بازگشت پس از رد» (`AD-06`) تأیید شد، چرخهٔ تعمیر تکرارشدنی باشد (پرسش باز ۷).
### ۵.۷. `report_feedbacks` — بازخورد گزارش‌دهنده (تأیید/رد)
| ستون | نوع | Null | پیش‌فرض | محدودیت | توضیح | مرجع |
|---|---|---|---|---|---|---|
| `id` | `bigserial` | خیر | — | PK | — | — |
| `report_id` | `bigint` | خیر | — | FK (ترکیبی) | گزارش | `FR-14`، `US-05` |
| `repair_result_id` | `bigint` | خیر | — | FK → `repair_results.id` | نتیجهٔ تعمیر مورد بررسی | `US-05.feature` |
| `reporter_id` | `bigint` | خیر | — | FK (ترکیبی) | تأییدکننده | `US-05.feature` |
| `is_approved` | `boolean` | خیر | — | — | تأیید (`true`) یا رد (`false`) | `US-05.feature` |
| `rejection_reason` | `text` | بله | NULL | `CHECK` (بخش ۶) | دلیل رد | `US-05.feature` |
| `created_at` | `timestamptz` | خیر | `now()` | — | زمان ثبت | — |
**محدودیت‌های کلیدی:**
- `UNIQUE (report_id, repair_result_id)` → مانع ثبت دو بازخورد برای یک نتیجهٔ تعمیر؛ همین، کلیک دوباره روی «تأیید» را در سطح داده بی‌اثر می‌کند (`US-05.feature`).
- `FOREIGN KEY (report_id, reporter_id) REFERENCES fault_reports (id, reporter_id)` → **در سطح داده** تضمین می‌کند فقط گزارش‌دهندهٔ همان گزارش می‌تواند بازخورد بدهد (`US-05.feature`).
- `CHECK (is_approved OR (rejection_reason IS NOT NULL AND btrim(rejection_reason) <> ''))` → دلیل رد اجباری (`US-05.feature`).
- `CHECK (NOT is_approved OR rejection_reason IS NULL)` → در حالت تأیید، دلیل رد نباید مقدار داشته باشد.
> **محدودیتی که در داده قابل اعمال نیست:** «تأیید فقط در وضعیت `REPAIRED` مجاز است» یک قاعدهٔ **بین‌جدولی** است و باید در لایهٔ اپلیکیشن (داخل یک تراکنش با قفل ردیف گزارش) یا با تریگر پیاده شود. در بخش ۶ توضیح داده شده است.
### ۵.۸. `report_history` — تاریخچهٔ اقدامات
| ستون | نوع | Null | پیش‌فرض | محدودیت | توضیح | مرجع |
|---|---|---|---|---|---|---|
| `id` | `bigserial` | خیر | — | PK | — | — |
| `report_id` | `bigint` | خیر | — | FK → `fault_reports.id` | گزارش | `FR-16`، `US-10` |
| `action_code` | `varchar(40)` | خیر | — | `CHECK` (بخش ۶) | نوع اقدام | `FR-16`، `US-05.feature` |
| `actor_id` | `bigint` | بله | NULL | FK → `users.id` | انجام‌دهنده (NULL برای اقدام سیستمی) | `FR-16` |
| `details` | `jsonb` | بله | NULL | — | جزئیات (مثلاً دلیل رد) | `US-05.feature` |
| `occurred_at` | `timestamptz` | خیر | `now()` | — | زمان وقوع | `US-10` |
**مقادیر مجاز `action_code`:** `REPORT_SUBMITTED`، `SUPPLEMENTARY_INFO_ADDED`، `INFO_REQUESTED`، `INFO_PROVIDED`، `PRIORITY_ASSIGNED`، `TECHNICIAN_ASSIGNED`، `REPAIR_STARTED`، `REPAIR_RESULT_RECORDED`، `REPAIR_APPROVED`، `REPAIR_REJECTED`، `REPORT_CLOSED`.
> **نکته:** این جدول **append-only** است. `UPDATE` و `DELETE` روی آن مجاز نیست و باید با مجوزهای پایگاه‌داده یا تریگر مسدود شود (`NFR-05`).
### ۵.۹. `notifications` — اعلان‌ها
| ستون | نوع | Null | پیش‌فرض | محدودیت | توضیح | مرجع |
|---|---|---|---|---|---|---|
| `id` | `bigserial` | خیر | — | PK | — | — |
| `recipient_id` | `bigint` | خیر | — | FK → `users.id` | گیرنده | `FR-15`، `US-16` |
| `report_id` | `bigint` | بله | NULL | FK → `fault_reports.id` | گزارش مرتبط | `US-16` |
| `event_code` | `varchar(40)` | خیر | — | `CHECK` | رویداد مبدأ | `FR-15` |
| `channel_code` | `varchar(20)` | خیر | — | FK → `notification_channels.code` | کانال ارسال | **پرسش باز ۸** |
| `is_read` | `boolean` | خیر | `false` | — | خوانده‌شده | — |
| `created_at` | `timestamptz` | خیر | `now()` | — | زمان ایجاد | — |
| `read_at` | `timestamptz` | بله | NULL | `CHECK ((is_read) = (read_at IS NOT NULL))` | زمان خواندن | — |
> **مقادیر مجاز `event_code`:** همان مقادیر `action_code` در `report_history` (بخش ۵.۸) به‌اضافهٔ `LOGIN_FAILED` در صورت نیاز.
## ۶. کلیدها و محدودیت‌ها — خلاصه
### ۶.۱. کلیدهای اصلی و یکتا
| جدول | PK | UK |
|---|---|---|
| `roles` | `code` | — |
| `report_statuses` | `code` | — |
| `priorities` | `code` | — |
| `equipment_types` | `code` | — |
| `notification_channels` | `code` | — |
| `users` | `id` | `username` |
| `fault_reports` | `id` | `report_no`، `(id, reporter_id)` |
| `report_supplementary_info` | `id` | — |
| `report_info_requests` | `id` | `response_info_id` |
| `report_assignments` | `id` | — |
| `repair_results` | `id` | — |
| `report_feedbacks` | `id` | `(report_id, repair_result_id)` |
| `report_history` | `id` | — |
| `notifications` | `id` | — |
### ۶.۲. محدودیت‌های `CHECK` تأییدشده
| قاعده | جدول | مستند مرجع |
|---|---|---|
| عنوان بین ۱ و ۱۵۰ کاراکتر | `fault_reports` | `US-01.feature` |
| عنوان، توضیحات، محل، نوع تجهیز خالی نباشند | `fault_reports` | `US-01.feature` |
| وضعیت اولیه `SUBMITTED` | `fault_reports` (DEFAULT) | `US-01.feature` |
| دلیل رد هنگام رد اجباری باشد | `report_feedbacks` | `US-05.feature` |
| دلیل رد هنگام تأیید خالی باشد | `report_feedbacks` | `US-05.feature` |
| تأییدکننده همان گزارش‌دهنده باشد | `report_feedbacks` (FK ترکیبی) | `US-05.feature` |
| یک بازخورد per نتیجهٔ تعمیر | `report_feedbacks` (UNIQUE) | `US-05.feature` |
| `read_at` با `is_read` هم‌خوان باشد | `notifications` | — |
### ۶.۳. قواعدی که در داده قابل اعمال نیستند (لایهٔ اپلیکیشن یا تریگر)
| قاعده | دلیل | مستند مرجع |
|---|---|---|
| تأیید فقط در وضعیت `REPAIRED` | قاعدهٔ بین‌جدولی | `US-05.feature` |
| تغییر وضعیت فقط از طریق انتقال‌های مجاز | وابسته به پرسش باز ۴ | `activity.md` |
| `closed_at` هنگام `CLOSED` پر باشد | قاعدهٔ بین‌ستونیِ وابسته به جدول مرجع | `US-05.feature` |
| دسترسی مبتنی بر نقش | قاعدهٔ لایهٔ اپلیکیشن | `FR-02`، `US-15.feature` |
| پیام خطای ورود مبهم باشد | قاعدهٔ لایهٔ اپلیکیشن | `US-15.feature` |
## ۷. ایندکس‌ها
| جدول | ایندکس | نوع | دلیل |
|---|---|---|---|
| `users` | `(username)` | UNIQUE | ورود سریع، `US-15` |
| `fault_reports` | `(report_no)` | UNIQUE | جست‌وجو با شناسهٔ نمایشی |
| `fault_reports` | `(reporter_id, created_at DESC)` | عادی | «گزارش‌های من»، `FR-05`، `US-03` |
| `fault_reports` | `(status_code, priority_code, created_at DESC)` | عادی | فهرست و فیلتر گزارش‌های باز، `FR-08`، `US-06` |
| `fault_reports` | `(report_id)` روی `(status_code)` WHERE `status_code <> 'CLOSED'` | جزئی | کوئری «گزارش‌های باز» و داشبورد، `FR-17` |
| `report_assignments` | `(technician_id, status)` | عادی | «مأموریت‌های من»، `FR-10`، `US-11` |
| `report_assignments` | `(report_id)` WHERE `status IN ('ASSIGNED','STARTED')` | جزئی (اختیاری) | فقط اگر پاسخ پرسش باز ۵ «یک تعمیرکار هم‌زمان» باشد |
| `report_feedbacks` | `(report_id, repair_result_id)` | UNIQUE | ایدمپوتنسی تأیید، `US-05.feature` |
| `report_history` | `(report_id, occurred_at DESC)` | عادی | نمایش تاریخچه، `FR-16`، `US-10` |
| `notifications` | `(recipient_id, is_read, created_at DESC)` | عادی | فهرست اعلان‌های خوانده‌نشده |
| `report_supplementary_info` | `(report_id, created_at)` | عادی | نمایش اطلاعات تکمیلی |
## ۸. ماشین حالت در داده
جدول `report_status_transitions` (اختیاری) ماشین حالت را از کد به **داده** منتقل می‌کند و مستقیماً به پرسش باز ۴ پاسخ می‌دهد:
| from_status_code | to_status_code | action_code | وضعیت |
|---|---|---|---|
| `SUBMITTED` | `ASSIGNED` | `TECHNICIAN_ASSIGNED` | ✅ تأییدشده (`AD-03`، `FR-09`) |
| `ASSIGNED` | `IN_REPAIR` | `REPAIR_STARTED` | ✅ تأییدشده (`AD-04`، `US-12`) |
| `IN_REPAIR` | `REPAIRED` | `REPAIR_RESULT_RECORDED` | ✅ تأییدشده (`AD-04`، `US-13`) |
| `REPAIRED` | `CLOSED` | `REPAIR_APPROVED` | ✅ تأییدشده (`AD-05`، `US-05.feature`) |
| `REPAIRED` | ؟ | `REPAIR_REJECTED` | ❓ **پرسش باز ۷** |
| `IN_REPAIR` | ؟ (انتظار اطلاعات) | `INFO_REQUESTED` | ❓ **پرسش باز ۶** |
مزیت: انتقال‌های تأییدشده همین حالا قابل seed هستند و انتقال‌های نامشخص بعداً **فقط با درج ردیف** اضافه می‌شوند، بدون تغییر کد.
## ۹. یادداشت‌های نرمال‌سازی و نگهداشت
- **فرم نرمال سوم (3NF):** همهٔ جداول در 3NF هستند؛ نام‌های تکراری (وضعیت، اولویت، نوع تجهیز، نقش، کانال) به جداول مرجع منتقل شده‌اند.
- **عدم تکرار داده:** وضعیت جاری **فقط** در `fault_reports.status_code` نگهداری می‌شود و در `report_history` به‌عنوان رویداد ثبت می‌شود؛ وضعیت در دو جا ذخیره نمی‌شود.
- **`report_history` به‌عنوان audit trail:** این جدول عمداً denormalize نشده و جزئیات در `jsonb` نگهداری می‌شود تا افزودن فیلدهای آینده بدون مهاجرت ممکن باشد.
- **نگهداشت (`NFR-05`):** حذف فیزیکی گزارش و تاریخچه ممنوع است. سیاست دقیق نگهداشت و آرشیو باید تعیین شود (پرسش باز ۱۲).
- **قفل خوش‌بینانه:** `version` روی `fault_reports` و `users` برای جلوگیری از بازنویسی هم‌زمان. هنگام `UPDATE` باید `WHERE version = ?` اعمال و `version = version + 1` شود.
- **منطقهٔ زمانی:** همهٔ زمان‌ها `timestamptz` (با منطقهٔ زمانی) هستند، نه `timestamp` ساده.
## ۱۰. ردیابی به مستندات
| عنصر داده | مستند مرجع |
|---|---|
| `users`، `roles` | `FR-01`، `FR-02`، `US-15`، `AD-01` |
| `fault_reports` | `FR-03` تا `FR-05`، `FR-11`، `FR-14` تا `FR-16`، `US-01` تا `US-05`، `US-09`، `US-10`، `AD-02` تا `AD-06` |
| `report_supplementary_info` | `FR-04`، `US-04`، `AD-02`، `AD-04` |
| `report_info_requests` | `FR-13`، `US-14`، `AD-04` |
| `report_assignments` | `FR-09`، `US-08`، `US-11`، `AD-03`، `AD-04` |
| `repair_results` | `FR-12`، `US-13`، `AD-04` |
| `report_feedbacks` | `FR-14`، `US-05`، `AD-05`، `US-05.feature` |
| `report_history` | `FR-16`، `US-03`، `US-05`، `US-10`، `AD-03` |
| `notifications` | `FR-15`، `US-16`، `AD-04` |
| `report_statuses` | `US-01.feature`، `US-05.feature`، `US-12`، `AD-03` تا `AD-05` |
| `priorities` | `FR-07`، `US-07`، `AD-03` (سطوح: پرسش باز ۳) |
| `equipment_types` | `FR-03`، `US-01.feature`، `README.md` |
| محدودیت ۱۵۰ کاراکتر و فیلدهای اجباری | `US-01.feature` |
| محدودیت‌های تأیید/رد | `US-05.feature` |
| یکتایی نام کاربری و هش رمز | `FR-01`، `US-15.feature`، `NFR-01` |
## ۱۱. پیوست — DDL مرجع (PostgreSQL)
> ⚠️ این پیوست **غیرالزام‌آور** است و فقط برای نشان‌دادن نگاشت مدل منطقی به یک پیاده‌سازی مشخص آورده شده. اگر تیم DBMS دیگری انتخاب کند (مثلاً MySQL)، این DDL باید معادل‌سازی شود و بخش‌های `jsonb`، `bigserial`، `timestamptz` و ایندکس‌های جزئی نیاز به تطبیق دارند.
```sql
-- =========================================================
-- مرجع DDL – PostgreSQL
-- =========================================================
-- ۱) جداول مرجع
CREATE TABLE roles (
code varchar(30) PRIMARY KEY,
label_fa varchar(60) NOT NULL,
sort_order smallint NOT NULL DEFAULT 0,
is_active boolean NOT NULL DEFAULT true
);
CREATE TABLE report_statuses (
code varchar(30) PRIMARY KEY,
label_fa varchar(60) NOT NULL,
sort_order smallint NOT NULL DEFAULT 0,
is_active boolean NOT NULL DEFAULT true
);
CREATE TABLE priorities (
code varchar(30) PRIMARY KEY,
label_fa varchar(60) NOT NULL,
sort_order smallint NOT NULL DEFAULT 0,
is_active boolean NOT NULL DEFAULT true
);
CREATE TABLE equipment_types (
code varchar(30) PRIMARY KEY,
label_fa varchar(60) NOT NULL,
sort_order smallint NOT NULL DEFAULT 0,
is_active boolean NOT NULL DEFAULT true
);
CREATE TABLE notification_channels (
code varchar(20) PRIMARY KEY,
label_fa varchar(60) NOT NULL,
is_active boolean NOT NULL DEFAULT true
);
-- ۲) دادهٔ اولیهٔ جداول مرجع
INSERT INTO roles (code, label_fa, sort_order) VALUES
('STUDENT', 'دانشجو', 10),
('PROFESSOR', 'استاد', 20),
('FACILITIES_STAFF', 'کارمند تأسیسات', 30),
('TECHNICIAN', 'تعمیرکار', 40),
('MANAGER', 'مدیر', 50);
INSERT INTO report_statuses (code, label_fa, sort_order) VALUES
('SUBMITTED', 'ثبت‌شده', 10),
('ASSIGNED', 'ارجاع‌شده', 20),
('IN_REPAIR', 'در حال تعمیر', 30),
('REPAIRED', 'تعمیر انجام‌شده', 40),
('CLOSED', 'بسته‌شده', 50);
-- سطوح اولویت موقت هستند (پرسش باز ۳)
INSERT INTO priorities (code, label_fa, sort_order) VALUES
('LOW', 'کم', 10),
('MEDIUM', 'متوسط', 20),
('HIGH', 'زیاد', 30),
('URGENT', 'فوری', 40);
INSERT INTO equipment_types (code, label_fa, sort_order) VALUES
('LIGHTING', 'روشنایی', 10),
('HVAC', 'تهویه', 20),
('ELEVATOR', 'آسانسور', 30),
('ELECTRICAL', 'برق', 40),
('PROJECTOR', 'پروژکتور', 50),
('OTHER', 'سایر', 60);
-- کانال‌ها تأییدنشده‌اند (پرسش باز ۸)
INSERT INTO notification_channels (code, label_fa) VALUES
('IN_APP', 'داخل سامانه'),
('SMS', 'پیامک'),
('EMAIL', 'ایمیل');
-- ۳) کاربران
CREATE TABLE users (
id bigserial PRIMARY KEY,
username varchar(50) NOT NULL,
password_hash varchar(255) NOT NULL,
role_code varchar(30) NOT NULL REFERENCES roles(code),
display_name varchar(100),
is_active boolean NOT NULL DEFAULT true,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
version integer NOT NULL DEFAULT 1,
CONSTRAINT uq_users_username UNIQUE (username),
CONSTRAINT ck_users_username_not_blank CHECK (btrim(username) <> '')
);
-- ۴) گزارش خرابی
CREATE TABLE fault_reports (
id bigserial PRIMARY KEY,
report_no varchar(20) NOT NULL,
title varchar(150) NOT NULL,
description text NOT NULL,
location_text varchar(255) NOT NULL,
equipment_type_code varchar(30) NOT NULL REFERENCES equipment_types(code),
status_code varchar(30) NOT NULL DEFAULT 'SUBMITTED'
REFERENCES report_statuses(code),
priority_code varchar(30) REFERENCES priorities(code),
reporter_id bigint NOT NULL REFERENCES users(id),
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),
closed_at timestamptz,
version integer NOT NULL DEFAULT 1,
CONSTRAINT uq_fault_reports_no UNIQUE (report_no),
CONSTRAINT uq_fault_reports_id_reporter UNIQUE (id, reporter_id),
CONSTRAINT ck_fault_reports_title CHECK (char_length(title) BETWEEN 1 AND 150),
CONSTRAINT ck_fault_reports_description CHECK (btrim(description) <> ''),
CONSTRAINT ck_fault_reports_location CHECK (btrim(location_text) <> '')
);
-- ۵) اطلاعات تکمیلی
CREATE TABLE report_supplementary_info (
id bigserial PRIMARY KEY,
report_id bigint NOT NULL REFERENCES fault_reports(id),
info_type varchar(20) NOT NULL,
content_text text,
attachment_ref varchar(500),
provided_by_id bigint NOT NULL REFERENCES users(id),
created_at timestamptz NOT NULL DEFAULT now(),
CONSTRAINT ck_supp_info_type CHECK (info_type IN ('TEXT','IMAGE')),
CONSTRAINT ck_supp_info_content CHECK (
(info_type = 'TEXT' AND content_text IS NOT NULL) OR
(info_type = 'IMAGE' AND attachment_ref IS NOT NULL)
)
);
-- ۶) درخواست اطلاعات
CREATE TABLE report_info_requests (
id bigserial PRIMARY KEY,
report_id bigint NOT NULL REFERENCES fault_reports(id),
requested_by_id bigint NOT NULL REFERENCES users(id),
description text NOT NULL,
requested_at timestamptz NOT NULL DEFAULT now(),
responded_at timestamptz,
response_info_id bigint UNIQUE REFERENCES report_supplementary_info(id),
CONSTRAINT ck_info_request_description CHECK (btrim(description) <> '')
);
-- ۷) تخصیص تعمیرکار
CREATE TABLE report_assignments (
id bigserial PRIMARY KEY,
report_id bigint NOT NULL REFERENCES fault_reports(id),
technician_id bigint NOT NULL REFERENCES users(id),
assigned_by_id bigint NOT NULL REFERENCES users(id),
assigned_at timestamptz NOT NULL DEFAULT now(),
status varchar(20) NOT NULL DEFAULT 'ASSIGNED',
CONSTRAINT ck_assignment_status
CHECK (status IN ('ASSIGNED','STARTED','DONE','CANCELLED'))
);
-- ۸) نتیجهٔ تعمیر
CREATE TABLE repair_results (
id bigserial PRIMARY KEY,
report_id bigint NOT NULL REFERENCES fault_reports(id),
technician_id bigint NOT NULL REFERENCES users(id),
description text NOT NULL,
recorded_at timestamptz NOT NULL DEFAULT now(),
CONSTRAINT ck_repair_result_description CHECK (btrim(description) <> '')
);
-- ۹) بازخورد گزارش‌دهنده
CREATE TABLE report_feedbacks (
id bigserial PRIMARY KEY,
report_id bigint NOT NULL,
repair_result_id bigint NOT NULL REFERENCES repair_results(id),
reporter_id bigint NOT NULL,
is_approved boolean NOT NULL,
rejection_reason text,
created_at timestamptz NOT NULL DEFAULT now(),
CONSTRAINT uq_feedback_per_result UNIQUE (report_id, repair_result_id),
CONSTRAINT fk_feedback_reporter
FOREIGN KEY (report_id, reporter_id)
REFERENCES fault_reports (id, reporter_id),
CONSTRAINT ck_feedback_rejection_reason_required
CHECK (is_approved OR (rejection_reason IS NOT NULL
AND btrim(rejection_reason) <> '')),
CONSTRAINT ck_feedback_rejection_reason_absent
CHECK (NOT is_approved OR rejection_reason IS NULL)
);
-- ۱۰) تاریخچه (append-only)
CREATE TABLE report_history (
id bigserial PRIMARY KEY,
report_id bigint NOT NULL REFERENCES fault_reports(id),
action_code varchar(40) NOT NULL,
actor_id bigint REFERENCES users(id),
details jsonb,
occurred_at timestamptz NOT NULL DEFAULT now(),
CONSTRAINT ck_history_action CHECK (action_code IN (
'REPORT_SUBMITTED','SUPPLEMENTARY_INFO_ADDED','INFO_REQUESTED',
'INFO_PROVIDED','PRIORITY_ASSIGNED','TECHNICIAN_ASSIGNED',
'REPAIR_STARTED','REPAIR_RESULT_RECORDED','REPAIR_APPROVED',
'REPAIR_REJECTED','REPORT_CLOSED'
))
);
-- جلوگیری از تغییر تاریخچه (NFR-05)
CREATE RULE report_history_no_update AS
ON UPDATE TO report_history DO INSTEAD NOTHING;
CREATE RULE report_history_no_delete AS
ON DELETE TO report_history DO INSTEAD NOTHING;
-- ۱۱) اعلان‌ها
CREATE TABLE notifications (
id bigserial PRIMARY KEY,
recipient_id bigint NOT NULL REFERENCES users(id),
report_id bigint REFERENCES fault_reports(id),
event_code varchar(40) NOT NULL,
channel_code varchar(20) NOT NULL REFERENCES notification_channels(code),
is_read boolean NOT NULL DEFAULT false,
created_at timestamptz NOT NULL DEFAULT now(),
read_at timestamptz,
CONSTRAINT ck_notifications_read_consistency
CHECK (is_read = (read_at IS NOT NULL))
);
-- ۱۲) ماشین حالت (اختیاری – پاسخ به پرسش باز ۴)
CREATE TABLE report_status_transitions (
from_status_code varchar(30) NOT NULL REFERENCES report_statuses(code),
to_status_code varchar(30) NOT NULL REFERENCES report_statuses(code),
action_code varchar(40) NOT NULL,
is_enabled boolean NOT NULL DEFAULT true,
PRIMARY KEY (from_status_code, to_status_code, action_code)
);
-- فقط انتقال‌های تأییدشده seed می‌شوند؛
-- انتقال‌های نامشخص (پرسش باز ۶ و ۷) عمداً درج نشده‌اند.
INSERT INTO report_status_transitions
(from_status_code, to_status_code, action_code) VALUES
('SUBMITTED', 'ASSIGNED', 'TECHNICIAN_ASSIGNED'),
('ASSIGNED', 'IN_REPAIR', 'REPAIR_STARTED'),
('IN_REPAIR', 'REPAIRED', 'REPAIR_RESULT_RECORDED'),
('REPAIRED', 'CLOSED', 'REPAIR_APPROVED');
-- ۱۳) ایندکس‌ها
CREATE INDEX ix_fault_reports_reporter
ON fault_reports (reporter_id, created_at DESC);
CREATE INDEX ix_fault_reports_status_priority
ON fault_reports (status_code, priority_code, created_at DESC);
CREATE INDEX ix_fault_reports_open
ON fault_reports (created_at DESC)
WHERE status_code <> 'CLOSED';
CREATE INDEX ix_assignments_technician
ON report_assignments (technician_id, status);
CREATE INDEX ix_history_report
ON report_history (report_id, occurred_at DESC);
CREATE INDEX ix_notifications_recipient
ON notifications (recipient_id, is_read, created_at DESC);
CREATE INDEX ix_supp_info_report
ON report_supplementary_info (report_id, created_at);
-- ۱۴) داشبورد – VIEW (نه جدول)
CREATE VIEW v_dashboard_summary AS
SELECT
count(*) FILTER (WHERE status_code <> 'CLOSED') AS open_reports,
count(*) FILTER (WHERE priority_code = 'URGENT'
AND status_code <> 'CLOSED') AS urgent_open_reports,
count(*) AS total_reports
FROM fault_reports;
```
## ۱۲. نکات و پرسش‌های باز
پرسش‌های باز موجود در [`activity.md`](activity.md) که مستقیماً بر مدل داده اثر می‌گذارند، به‌همراه پرسش‌های جدیدی که خود مدل داده ایجاد کرده است:
### ۱۲.۱. پرسش‌های باز اثرگذار بر مدل داده
| # | پرسش | اثر بر مدل داده | مرجع |
|---|---|---|---|
| ۳ | سطوح و معیارهای اولویت چیست؟ | مقادیر `priorities` موقت‌اند | `activity.md` |
| ۴ | فهرست رسمی وضعیت‌ها و انتقال‌های مجاز چیست؟ | محتوای `report_statuses` و `report_status_transitions` | `activity.md` |
| ۵ | یک گزارش به یک یا چند تعمیرکار تخصیص می‌یابد؟ | افزودن ایندکس یگانهٔ جزئی در صورت «یک تعمیرکار» | `activity.md` |
| ۶ | چه کسانی مجاز به درخواست/ارائهٔ اطلاعات هستند؟ | کنترل در لایهٔ اپلیکیشن؛ ستون‌ها فعلاً عمومی‌اند | `activity.md` |
| ۷ | پس از رد تعمیر چه اتفاقی می‌افتد؟ | انتقال جدید در `report_status_transitions`؛ شاید ستون `is_flagged_for_followup` | `activity.md` |
| ۸ | کانال اعلان چیست؟ | مقادیر `notification_channels` تأییدنشده | `activity.md` |
| ۹ | آیا یک کاربر می‌تواند چند نقش داشته باشد؟ | **تعیین‌کننده:** ستون `role_code` یا جدول `user_roles` | `activity.md` |
| ۱۰ | روش احراز هویت و بازیابی رمز چیست؟ | ممکن است جدول `password_reset_tokens` و `login_attempts` لازم شود | `activity.md` |
### ۱۲.۲. پرسش‌های باز جدید (ایجادشده توسط مدل داده)
| # | پرسش | پیشنهاد پیش‌فرض |
|---|---|---|
| ۱۱ | فرمت و روش تولید `report_no` چیست؟ (توالی، تصادفی، شامل سال؟) | `R-` + توالی یکتا؛ الگوی دقیق باید تعیین شود |
| ۱۲ | آیا حذف منطقی گزارش لازم است یا بستن (`CLOSED`) کافی است؟ | فعلاً بستن کافی است (`NFR-05`) |
| ۱۳ | آیا ثبت تلاش‌های ورود ناموفق برای audit لازم است؟ | در مستندات الزام نشده؛ در صورت نیاز جدول `login_attempts` اضافه شود |
| ۱۴ | آیا محل خرابی باید ساختاریافته شود (ساختمان/طبقه/اتاق)؟ | تا تعیین ابهام دامنه، `location_text` کافی است (تصمیم D2) |
| ۱۵ | سیاست نگهداشت و آرشیو گزارش‌های بسته‌شده چیست؟ | باید در `NFR-05` یا سند جداگانه تعیین شود |
### ۱۲.۳. ناسازگاری‌هایی که باید در بازبینی حل شوند
1. **`location_text` در برابر `Location` ساختاریافته:** `class-diagram.md` و `domain-model.md` محل را ساختاریافته مدل کرده‌اند، اما `US-01.feature` آن را یک فیلد متنی می‌داند. تصمیم D2 این سند، متن آزاد است. باید یکی از دو سند همراستا شود.
2. **ارث‌بری نقش در برابر ستون `role_code`:** `class-diagram.md` از ارث‌بری استفاده می‌کند، `domain-model.md` نقش را Value Object چندمقداری دیده و این سند یک ستون واحد دارد. پاسخ پرسش باز ۹ باید **هر سه سند را هم‌زمان** به‌روزرسانی کند.
3. **`Dashboard`:** در `class-diagram.md` یک کلاس است، در این سند یک `VIEW`. این تفاوت عمدی است و باید در `class-diagram.md` با برچسب `Read Model` شفاف‌تر شود.
---
**وضعیت سند:** نسخه اولیه (Draft) – آماده بازبینی
+3 -2
View File
@@ -28,6 +28,7 @@
- **تعمیرکار:** مشاهدهٔ درخواست‌های تخصیص‌یافته، انجام تعمیرات و ثبت نتیجهٔ اقدامات.
- **مدیر:** نظارت بر عملکرد کلی سامانه و مشاهدهٔ اطلاعات و گزارش‌های مدیریتی.
- **کاربر سیستم:** عنوان عمومی برای اشاره به کاربران دارای حساب کاربری و دسترسی به سامانه.
- **گزارش‌دهنده:** عنوان مشترک دانشجو و استاد در فرایند ثبت و پیگیری گزارش خرابی.
## ۳. نیازمندی‌های کارکردی (Functional Requirements)
@@ -89,14 +90,14 @@
- **NFR-06 — قابلیت نگهداری:** ساختار سامانه باید امکان اصلاح، نگهداری و افزودن قابلیت‌های جدید را در آینده فراهم کند.
## ۵. نکات و کارهای باقی‌مانده
## ۵. نکات و پرسش‌های باز
- این نیازمندی‌ها نسخهٔ اولیه هستند و ممکن است در مراحل بعدی تحلیل و بازبینی تغییر کنند یا نیازمندی‌های جدیدی به آن‌ها اضافه شود.
- محدودهٔ دقیق فضاهای تحت پوشش سامانه، از جمله خوابگاه‌ها و فضاهای اداری، هنوز مشخص نشده است.
- معیارهای دقیق اولویت‌بندی خرابی‌ها و نحوهٔ تشخیص درخواست‌های فوری باید تعیین شوند.
- روش اطلاع‌رسانی به کاربران، مانند اعلان داخل سامانه، پیامک یا ایمیل، هنوز مشخص نشده است.
- جزئیات سطح دسترسی هر نقش و شرایط بسته‌شدن نهایی درخواست‌ها باید در مراحل بعدی مشخص شوند.
- نیازمندی‌های تعریف‌شده باید با داستان‌های کاربر (User Stories) و سایر مستندات پروژه تطبیق داده شوند.
- هر نیازمندی باید حداقل با یک داستان کاربر (User Story) تطبیق داده شود. ارجاع‌ها در فیلد «نیازمندی‌های مرتبط» همان سند [user-story.md](user-story.md) ثبت شده‌اند.
---
+371
View File
@@ -0,0 +1,371 @@
# معماری نرم‌افزار (Software Architecture) – سامانه مدیریت و گزارش خرابی دانشگاهی
**تهیه‌کننده:** ارشیا همتی‌زاده
**بازبین:** رضا آدوسی
**آخرین به‌روزرسانی:** ۱۴۰۵/۰۸/۱۴
---
## مقدمه
این سند معماری نرم‌افزاری سامانهٔ مدیریت و گزارش خرابی دانشگاهی را در سطح **منطقی و مفهومی** تعریف می‌کند. چون پروژه هنوز وارد فاز پیاده‌سازی نشده است (طبق `README.md`)، این سند **تعهد به فناوری خاصی ندارد** و انتخاب‌های فناورانه در بخش «پرسش‌های باز» علامت‌گذاری شده‌اند.
هدف این سند پاسخ به سه پرسش است:
1. سامانه از چه **مؤلفه‌هایی** تشکیل می‌شود و مرز مسئولیت هر کدام کجاست؟
2. این مؤلفه‌ها چگونه با هم **همکاری** می‌کنند تا جریان‌های توصیف‌شده در `activity.md` محقق شوند؟
3. کدام **نیروهای محرک معماری (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`) کار می‌کنند. جداسازی این دو **ماژول منطقی** است، نه فیزیکی. مزیت: هر ماژول فقط متدهای مجاز خودش را روی گزارش فراخوانی می‌کند و قانون «تغییر وضعیت فقط از مسیر مجاز» در یک نقطه کنترل می‌شود.
## ۴. لایه‌های معماری
```mermaid
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)
```mermaid
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)
```mermaid
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)
```mermaid
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)
```mermaid
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)
```mermaid
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)
```mermaid
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) – آماده بازبینی
+460
View File
@@ -0,0 +1,460 @@
# رابط کاربری و وایرفریم‌ها (UI Wireframes) – سامانه مدیریت و گزارش خرابی دانشگاهی
**تهیه‌کننده:** ارشیا همتی‌زاده
**بازبین:** رضا آدوسی
**آخرین به‌روزرسانی:** ۱۴۰۵/۰۸/۱۴
---
## مقدمه
این سند فهرست صفحات، نقشهٔ ناوبری و طرح اولیهٔ چیدمان (Wireframe) رابط کاربری سامانه را ارائه می‌دهد. هدف، تبدیل داستان‌های کاربر و جریان‌های `activity.md` به صفحات مشخص است، **پیش از** انتخاب فناوری و شروع کدنویسی.
> **نکتهٔ نمایش:** متن نهایی سامانه فارسی و راست‌به‌چپ (RTL) است. طرح‌های این سند با کاراکترهای ساده رسم شده‌اند و **جهت چیدمان آن‌ها نمایندهٔ جهت نهایی نیست**. در پیاده‌سازی، ستون «منو/اقدام» در سمت راست و ناحیهٔ محتوا در سمت چپ قرار می‌گیرد.
## ۱. اصول طراحی
| # | اصل | توضیح | مستند مرجع |
|---|---|---|---|
| P1 | **راست‌به‌چپ و فارسی** | همهٔ برچسب‌ها، پیام‌ها و تاریخ‌ها فارسی؛ تاریخ شمسی با ارقام فارسی | `NFR-03`، `CONTRIBUTING.md` §۷ |
| P2 | **ناوبری نقش‌محور** | هر کاربر فقط صفحات نقش خود را در منو می‌بیند | `FR-02`، `US-15` |
| P3 | **اعتبارسنجی درجا** | خطا کنار همان فیلد نمایش داده می‌شود، نه در بالای صفحه | `US-01.feature` |
| P4 | **حفظ ورودی در خطا** | در خطای اعتبارسنجی یا خطای سرور، مقادیر فرم پاک نمی‌شوند | `US-01.feature` |
| P5 | **افشا نکردن علت خطای ورود** | پیام ورود مبهم است و فیلد اشتباه را مشخص نمی‌کند | `US-15.feature` |
| P6 | **پنهان‌نکردن قابلیت به‌جای کنترل دسترسی** | مجوزدهی سمت سرور؛ رابط کاربری فقط بازتاب آن است | `ADR-03` در `software-architecture.md` |
| P7 | **بازخورد صریح وضعیت** | هر اقدام موفق یا ناموفق پیام روشن دارد | `NFR-03` |
| P8 | **نمایش وضعیت و اولویت به‌صورت بصری** | بج رنگی برای وضعیت و اولویت در همهٔ فهرست‌ها | `FR-08`، `US-06` |
## ۲. فهرست صفحات
| شناسه | صفحه | نقش‌های مجاز | داستان‌های کاربر | جریان فعالیت |
|---|---|---|---|---|
| `SCR-01` | ورود به سامانه | همه | `US-15` | `AD-01` |
| `SCR-02` | گزارش‌های من | دانشجو، استاد | `US-03` | `AD-02` |
| `SCR-03` | ثبت گزارش خرابی | دانشجو، استاد | `US-01`، `US-02` | `AD-02` |
| `SCR-04` | جزئیات گزارش (نمای گزارش‌دهنده) | دانشجو، استاد | `US-03`، `US-04`، `US-05` | `AD-02`، `AD-05` |
| `SCR-05` | فهرست گزارش‌های باز | کارمند تأسیسات | `US-06` | `AD-03` |
| `SCR-06` | جزئیات گزارش (نمای تأسیسات) | کارمند تأسیسات | `US-06`–`US-10` | `AD-03` |
| `SCR-07` | مأموریت‌های من | تعمیرکار | `US-11` | `AD-04` |
| `SCR-08` | جزئیات مأموریت | تعمیرکار | `US-12`، `US-13`، `US-14` | `AD-04` |
| `SCR-09` | داشبورد مدیریتی | کارمند تأسیسات، مدیر | `US-17` | `AD-03` |
| `SCR-10` | اعلان‌ها | همه | `US-16` | — |
| `SCR-11` | خطای دسترسی | همه | `US-15` | `AD-01` |
| `SCR-12` | مودال تأیید/رد تعمیر | دانشجو، استاد | `US-05` | `AD-05` |
## ۳. نقشهٔ ناوبری
```mermaid
flowchart TD
LOGIN["SCR-01<br/>ورود"] --> ROLE{"نقش کاربر"}
ROLE -->|"دانشجو / استاد"| R_HOME["SCR-02<br/>گزارش‌های من"]
R_HOME --> R_NEW["SCR-03<br/>ثبت گزارش"]
R_HOME --> R_DETAIL["SCR-04<br/>جزئیات گزارش"]
R_DETAIL --> R_MODAL["SCR-12<br/>تأیید یا رد تعمیر"]
ROLE -->|"کارمند تأسیسات"| F_HOME["SCR-05<br/>گزارش‌های باز"]
F_HOME --> F_DETAIL["SCR-06<br/>جزئیات گزارش"]
F_HOME --> F_DASH["SCR-09<br/>داشبورد"]
ROLE -->|"تعمیرکار"| T_HOME["SCR-07<br/>مأموریت‌های من"]
T_HOME --> T_DETAIL["SCR-08<br/>جزئیات مأموریت"]
ROLE -->|"مدیر"| M_DASH["SCR-09<br/>داشبورد"]
R_HOME -.-> NOTIF["SCR-10<br/>اعلان‌ها"]
F_DETAIL -.-> NOTIF
T_DETAIL -.-> NOTIF
R_HOME -.->|"دسترسی غیرمجاز"| ERR["SCR-11<br/>خطای دسترسی"]
F_HOME -.-> ERR
T_HOME -.-> ERR
```
## ۴. وایرفریم‌ها
در هر طرح، کادرهای شماره‌دار به عناصر مشخص اشاره دارند و جدول زیر آن‌ها مشخصات کامل هر عنصر را می‌دهد. این روش از مشکل نمایش راست‌به‌چپ متن فارسی در بلوک کد جلوگیری می‌کند.
### ۴.۱. `SCR-01` — ورود به سامانه
```text
┌──────────────────────────────────────────────────────────────┐
│ [۱] [۲] │
│ │
│ ┌────────────────────────┐ │
│ │ [۳] │ │
│ │ │ │
│ │ [۴] │ │
│ │ ┌──────────────────┐ │ │
│ │ │ [۵] │ │ │
│ │ └──────────────────┘ │ │
│ │ [۶] │ │
│ │ ┌──────────────────┐ │ │
│ │ │ [۷] │ │ │
│ │ └──────────────────┘ │ │
│ │ [۸] │ │
│ │ ┌──────────────────┐ │ │
│ │ │ [۹] │ │ │
│ │ └──────────────────┘ │ │
│ └────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────┘
```
| # | عنصر | نوع | محتوا | رفتار | مرجع |
|---|---|---|---|---|---|
| ۱ | لوگو و نام سامانه | متن | «سامانه مدیریت و گزارش خرابی دانشگاهی» | — | `README.md` |
| ۲ | فضای خالی / زبان | — | فعلاً فقط فارسی | — | `NFR-03` |
| ۳ | عنوان فرم | تیتر | «ورود به سامانه» | — | `US-15` |
| ۴ | برچسب نام کاربری | متن | «نام کاربری» | — | `FR-01` |
| ۵ | ورودی نام کاربری | فیلد متنی | — | اجباری؛ در صورت خالی‌بودن: «این فیلد الزامی است» کنار فیلد | `US-15.feature` |
| ۶ | برچسب رمز عبور | متن | «رمز عبور» | — | `FR-01` |
| ۷ | ورودی رمز عبور | فیلد رمز | — | اجباری؛ ماسک‌شده | `US-15.feature` |
| ۸ | ناحیهٔ خطا | ناحیهٔ پیام | خالی در حالت عادی | در خطای ورود: «نام کاربری یا رمز عبور اشتباه است» — نام کاربری در فرم می‌ماند | `US-15.feature` |
| ۹ | دکمهٔ ورود | دکمهٔ اصلی | «ورود» | پس از موفقیت: انتقال به داشبورد نقش | `AD-01` |
**حالت‌های خطا:**
| حالت | پیام | رفتار | مرجع |
|---|---|---|---|
| فیلد خالی | «این فیلد الزامی است» (کنار همان فیلد) | ورود انجام نمی‌شود | `US-15.feature` |
| اعتبارنامهٔ نامعتبر | «نام کاربری یا رمز عبور اشتباه است» | نام کاربری حفظ می‌شود؛ فیلد اشتباه مشخص نمی‌شود | `US-15.feature` |
| سرویس احراز هویت در دسترس نیست | «خطا در ورود؛ لطفاً بعداً تلاش کنید» | ورود انجام نمی‌شود | `US-15.feature` |
> **الزام امنیتی:** هیچ پیام خطایی نباید مشخص کند «نام کاربری وجود ندارد» یا «رمز اشتباه است». تنها پیام مشترک مجاز است (P5).
### ۴.۲. `SCR-03` — ثبت گزارش خرابی
```text
┌──────────────────────────────────────────────────────────────┐
│ [۱] [۲] │
├──────────────┬───────────────────────────────────────────────┤
│ │ [۳] │
│ [M1] │ ┌──────────────────────────────────────────┐ │
│ [M2] │ │ [۴] │ │
│ [M3] │ │ ┌──────────────────────────────────────┐ │ │
│ [M4] │ │ │ [۵] │ │ │
│ │ │ └──────────────────────────────────────┘ │ │
│ │ │ [۶] │ │
│ │ │ ┌──────────────────────────────────────┐ │ │
│ │ │ │ [۷] │ │ │
│ │ │ │ │ │ │
│ │ │ └──────────────────────────────────────┘ │ │
│ │ │ [۸] │ │ │
│ │ │ ┌──────────────────────────────────────┐ │ │
│ │ │ │ [۹] │ │ │
│ │ │ └──────────────────────────────────────┘ │ │
│ │ │ [۱۰] │ │ │
│ │ │ ┌──────────────────────────────────────┐ │ │
│ │ │ │ [۱۱] │ │ │
│ │ │ └──────────────────────────────────────┘ │ │
│ │ │ [۱۲] [۱۳] │ │
│ │ └──────────────────────────────────────────┘ │
└──────────────┴───────────────────────────────────────────────┘
```
| # | عنصر | نوع | محتوا | رفتار | مرجع |
|---|---|---|---|---|---|
| ۱ | نوار بالا | ناحیه | نام کاربر + خروج | — | `FR-01` |
| ۲ | زنگ اعلان | آیکون + شمارنده | تعداد خوانده‌نشده | کلیک → `SCR-10` | `US-16` |
| M1–M4 | منوی نقش | فهرست | «گزارش‌های من»، «ثبت گزارش»، «اعلان‌ها»، «خروج» | فقط آیتم‌های مجاز نقش | `FR-02` |
| ۳ | عنوان صفحه | تیتر | «ثبت گزارش خرابی» | — | `US-01`، `US-02` |
| ۴ | برچسب عنوان | متن | «عنوان» + نشان اجباری | — | `FR-03` |
| ۵ | ورودی عنوان | فیلد متنی | — | اجباری؛ حداکثر ۱۵۰ کاراکتر؛ شمارندهٔ کاراکتر | `US-01.feature` |
| ۶ | برچسب توضیحات | متن | «توضیحات» + نشان اجباری | — | `FR-03` |
| ۷ | ورودی توضیحات | ناحیهٔ متنی | — | اجباری | `US-01.feature` |
| ۸ | برچسب محل خرابی | متن | «محل خرابی» + نشان اجباری | — | `FR-03` |
| ۹ | ورودی محل | فیلد متنی | نمونه: «ساختمان الف - کلاس ۱۰۲» | اجباری | `US-01.feature` |
| ۱۰ | برچسب نوع تجهیز | متن | «نوع تجهیز» + نشان اجباری | — | `FR-03` |
| ۱۱ | انتخاب نوع تجهیز | فهرست کشویی | روشنایی، تهویه، آسانسور، برق، پروژکتور، سایر | اجباری | `US-01.feature`، `README.md` |
| ۱۲ | دکمهٔ انصراف | دکمهٔ ثانویه | «انصراف» | بازگشت به `SCR-02` | — |
| ۱۳ | دکمهٔ ثبت | دکمهٔ اصلی | «ثبت گزارش» | ارسال؛ در انتظار: غیرفعال + نشانگر | `AD-02` |
**حالت‌های نتیجه:**
| حالت | پیام | رفتار | مرجع |
|---|---|---|---|
| موفقیت | نمایش شناسهٔ یکتا | انتقال به `SCR-04` یا ماندن با پیام موفقیت | `US-01.feature` |
| فیلد اجباری خالی | «این فیلد الزامی است» کنار فیلد | هیچ گزارشی ذخیره نمی‌شود | `US-01.feature` |
| عنوان ۱۵۱ کاراکتر | «حداکثر طول عنوان ۱۵۰ کاراکتر است» | هیچ گزارشی ذخیره نمی‌شود | `US-01.feature` |
| خطای سرور | «خطا در ثبت گزارش؛ لطفاً دوباره تلاش کنید» | **مقادیر فرم حفظ می‌شوند**، هیچ گزارش ناقصی ذخیره نمی‌شود | `US-01.feature` |
> **الزام P4:** در حالت خطای سرور، پاک‌کردن فرم **ممنوع** است. این رفتار در `US-01.feature` صریحاً الزام شده است.
### ۴.۳. `SCR-05` — فهرست گزارش‌های باز (کارمند تأسیسات)
```text
┌──────────────────────────────────────────────────────────────┐
│ [۱] [۲] │
├──────────────┬───────────────────────────────────────────────┤
│ │ [۳] │
│ [M1] │ [۴] [۵] [۶] [۷] │
│ [M2] │ ┌──────────────────────────────────────────┐ │
│ [M3] │ │ [۸] │ [۹] │ [۱۰] │ [۱۱] │ [۱۲] │ [۱۳] │ │
│ │ ├──────────────────────────────────────────┤ │
│ │ │ ... │ │
│ │ │ ... │ │
│ │ │ ... │ │
│ │ └──────────────────────────────────────────┘ │
│ │ [۱۴] │
└──────────────┴───────────────────────────────────────────────┘
```
| # | عنصر | نوع | محتوا | رفتار | مرجع |
|---|---|---|---|---|---|
| ۱ | نوار بالا | ناحیه | نام کاربر + خروج | — | — |
| ۲ | زنگ اعلان | آیکون | — | → `SCR-10` | `US-16` |
| M1–M4 | منوی نقش | فهرست | «گزارش‌های باز»، «داشبورد»، «اعلان‌ها»، «خروج» | — | `FR-02` |
| ۳ | عنوان صفحه | تیتر | «گزارش‌های باز» | — | `US-06` |
| ۴ | فیلتر وضعیت | کشویی چندگزینه | از `report_statuses` | پیش‌فرض: همه به‌جز «بسته‌شده» | `FR-08`، `US-06` |
| ۵ | فیلتر اولویت | کشویی چندگزینه | از `priorities` | — | `FR-08` |
| ۶ | جست‌وجو | فیلد متنی | جست‌وجو در عنوان و شناسه | — | `FR-08` |
| ۷ | دکمهٔ پاک‌کردن فیلتر | دکمهٔ ثانویه | «پاک‌کردن فیلترها» | بازنشانی | — |
| ۸ | ستون شناسه | ستون جدول | `report_no` | قابل مرتب‌سازی | — |
| ۹ | ستون عنوان | ستون جدول | عنوان گزارش | لینک به `SCR-06` | — |
| ۱۰ | ستون محل | ستون جدول | محل خرابی | — | `FR-03` |
| ۱۱ | ستون اولویت | ستون جدول | بج اولویت | رنگ‌بندی بر اساس سطح | `FR-07` |
| ۱۲ | ستون وضعیت | ستون جدول | بج وضعیت | رنگ‌بندی بر اساس وضعیت | `FR-11` |
| ۱۳ | ستون تاریخ | ستون جدول | تاریخ ثبت (شمسی) | مرتب‌سازی پیش‌فرض: نزولی | — |
| ۱۴ | صفحه‌بندی | ناحیه | تعداد در صفحه | — | `NFR-04` |
> **تعریف «باز»:** گزارشی که وضعیت آن «بسته‌شده» نیست. «باز» یک وضعیت رسمی نیست (`data-model.md` §۴.۲).
### ۴.۴. `SCR-06` — جزئیات گزارش (نمای تأسیسات)
```text
┌──────────────────────────────────────────────────────────────┐
│ [۱] [۲] │
├──────────────┬───────────────────────────────────────────────┤
│ [M1] │ [۳] [۴] [۵] │
│ [M2] │ ┌──────────────────┬────────────────────────┐ │
│ [M3] │ │ [۶] │ [۷] │ │
│ │ │ [۸] │ [۹] │ │
│ │ │ [۱۰] │ [۱۱] │ │
│ │ │ [۱۲] │ [۱۳] │ │
│ │ │ │ [۱۴] │ │
│ │ │ │ [۱۵] │ │
│ │ └──────────────────┴────────────────────────┘ │
│ │ [۱۶] │
│ │ ┌──────────────────────────────────────────┐ │
│ │ │ ... │ │
│ │ └──────────────────────────────────────────┘ │
└──────────────┴───────────────────────────────────────────────┘
```
| # | عنصر | نوع | محتوا | رفتار | مرجع |
|---|---|---|---|---|---|
| ۳ | عنوان گزارش | تیتر | عنوان + شناسه | — | `FR-03` |
| ۴ | بج وضعیت | بج | وضعیت جاری | — | `FR-11` |
| ۵ | بج اولویت | بج | اولویت (در صورت تعیین) | — | `FR-07` |
| ۶ | توضیحات | متن | توضیحات گزارش‌دهنده | — | `FR-03` |
| ۷ | محل خرابی | متن | متن محل | — | `FR-03` |
| ۸ | نوع تجهیز | متن | برچسب فارسی نوع | — | `FR-03` |
| ۹ | گزارش‌دهنده | متن | نام نمایشی + نقش | — | — |
| ۱۰ | تاریخ ثبت | متن | تاریخ شمسی | — | — |
| ۱۱ | اطلاعات تکمیلی | فهرست | متن/تصویر + ارائه‌دهنده + زمان | — | `FR-04`، `US-04` |
| ۱۲ | نتیجهٔ تعمیر | ناحیه | توضیحات + تعمیرکار + زمان | فقط در صورت وجود | `FR-12` |
| ۱۳ | تعیین اولویت | کشویی + دکمه | «ذخیرهٔ اولویت» | فقط نقش تأسیسات | `FR-07`، `US-07` |
| ۱۴ | تخصیص تعمیرکار | کشویی + دکمه | فهرست تعمیرکاران + «تخصیص» | فقط نقش تأسیسات | `FR-09`، `US-08` |
| ۱۵ | تغییر وضعیت | کشویی + دکمه | فقط انتقال‌های مجاز | گزینه‌های غیرمجاز نمایش داده نمی‌شوند | `FR-11`، `US-09` |
| ۱۶ | تاریخچه | تایم‌لاین | فهرست اقدامات به ترتیب زمانی | — | `FR-16`، `US-10` |
> **الزام ADR-06:** گزینه‌های کشویی «تغییر وضعیت» باید از جدول انتقال‌های مجاز خوانده شوند، نه از کد. انتقال‌های نامشخص (پرسش‌های باز ۶ و ۷) نباید در رابط کاربری ظاهر شوند تا زمانی که تیم تصمیم بگیرد.
### ۴.۵. `SCR-07` — مأموریت‌های من (تعمیرکار)
```text
┌──────────────────────────────────────────────────────────────┐
│ [۱] [۲] │
├──────────────┬───────────────────────────────────────────────┤
│ [M1] │ [۳] │
│ [M2] │ ┌──────────────────────────────────────────┐ │
│ │ │ [۴] │ [۵] │ [۶] │ [۷] │ [۸] │ [۹] │ │
│ │ ├──────────────────────────────────────────┤ │
│ │ │ ... │ │
│ │ └──────────────────────────────────────────┘ │
└──────────────┴───────────────────────────────────────────────┘
```
| # | عنصر | نوع | محتوا | رفتار | مرجع |
|---|---|---|---|---|---|
| ۳ | عنوان صفحه | تیتر | «مأموریت‌های من» | — | `US-11` |
| ۴ | ستون شناسه | ستون | `report_no` | — | — |
| ۵ | ستون عنوان | ستون | عنوان گزارش | لینک به `SCR-08` | — |
| ۶ | ستون محل | ستون | محل خرابی | — | — |
| ۷ | ستون اولویت | ستون | بج اولویت | — | `FR-07` |
| ۸ | ستون وضعیت | ستون | وضعیت تخصیص | — | `US-12`، `US-13` |
| ۹ | ستون زمان تخصیص | ستون | تاریخ شمسی | — | — |
> **واژه‌شناسی:** «مأموریت» در `US-11` و `AD-04` همان «تخصیص» در `FR-09` است. رابط کاربری از واژهٔ «مأموریت» استفاده می‌کند چون زبان تعمیرکار است.
### ۴.۶. `SCR-08` — جزئیات مأموریت (تعمیرکار)
```text
┌──────────────────────────────────────────────────────────────┐
│ [۱] [۲] │
├──────────────┬───────────────────────────────────────────────┤
│ [M1] │ [۳] [۴] │
│ │ ┌──────────────────────────────────────────┐ │
│ │ │ [۵] [۶] [۷] │ │
│ │ └──────────────────────────────────────────┘ │
│ │ [۸] │
│ │ ┌──────────────────────────────────────────┐ │
│ │ │ [۹] │ │
│ │ └──────────────────────────────────────────┘ │
│ │ [۱۰] [۱۱] [۱۲] │
│ │ [۱۳] │
│ │ ┌──────────────────────────────────────────┐ │
│ │ │ ... │ │
│ │ └──────────────────────────────────────────┘ │
└──────────────┴───────────────────────────────────────────────┘
```
| # | عنصر | نوع | محتوا | رفتار | مرجع |
|---|---|---|---|---|---|
| ۳ | عنوان + شناسه | تیتر | — | — | — |
| ۴ | بج وضعیت | بج | — | — | `FR-11` |
| ۵ | توضیحات خرابی | متن | — | — | `FR-03` |
| ۶ | محل خرابی | متن | — | — | — |
| ۷ | نوع تجهیز | متن | — | — | — |
| ۸ | دکمهٔ «شروع تعمیر» | دکمه | فقط در وضعیت «ارجاع‌شده» | تغییر وضعیت به «در حال تعمیر» | `US-12` |
| ۹ | فرم ثبت نتیجه | ناحیهٔ متنی + دکمه | توضیحات اقدامات | فقط پس از شروع تعمیر | `FR-12`، `US-13` |
| ۱۰ | دکمهٔ «ثبت نتیجه» | دکمهٔ اصلی | — | تغییر وضعیت به «تعمیر انجام‌شده» | `US-13` |
| ۱۱ | دکمهٔ «درخواست اطلاعات» | دکمهٔ ثانویه | — | باز شدن فرم درخواست | `FR-13`، `US-14` |
| ۱۲ | فرم درخواست اطلاعات | ناحیهٔ متنی + دکمه | متن درخواست | ارسال به گزارش‌دهنده | `US-14`، `AD-04` |
| ۱۳ | تاریخچه | تایم‌لاین | — | — | `FR-16` |
> **پرسش باز ۶:** مکانیزم دقیق «انتظار برای دریافت اطلاعات» در `AD-04` علامت‌گذاری شده است. آیا وضعیت گزارش باید تغییر کند؟ تا تصمیم‌گیری، رابط کاربری فقط نشانگر «در انتظار پاسخ» نمایش می‌دهد و وضعیت گزارش را تغییر نمی‌دهد.
### ۴.۷. `SCR-09` — داشبورد مدیریتی
```text
┌──────────────────────────────────────────────────────────────┐
│ [۱] [۲] │
├──────────────┬───────────────────────────────────────────────┤
│ [M1] │ [۳] │
│ [M2] │ ┌───────────┬───────────┬───────────┐ │
│ │ │ [۴] │ [۵] │ [۶] │ │
│ │ └───────────┴───────────┴───────────┘ │
│ │ [۷] │
│ │ ┌──────────────────────────────────────────┐ │
│ │ │ [۸] │ │
│ │ └──────────────────────────────────────────┘ │
└──────────────┴───────────────────────────────────────────────┘
```
| # | عنصر | نوع | محتوا | مرجع |
|---|---|---|---|---|
| ۳ | عنوان | تیتر | «داشبورد» | `US-17` |
| ۴ | کارت آمار | کارت | تعداد گزارش‌های باز | `FR-17` |
| ۵ | کارت آمار | کارت | تعداد درخواست‌های فوری | `FR-17`، `US-17` |
| ۶ | کارت آمار | کارت | تعداد کل گزارش‌ها | `FR-17` |
| ۷ | نمودار / فهرست | ناحیه | توزیع گزارش‌ها بر اساس وضعیت | `FR-17` |
| ۸ | فهرست کوتاه | جدول | آخرین گزارش‌های فوری | `US-17` |
> **تفکیک نقش:** مدیر فقط مشاهده دارد (`FR-17`، `US-17`). کارمند تأسیسات علاوه بر داشبورد به `SCR-05` و `SCR-06` هم دسترسی دارد. سطح دسترسی کامل مدیر پرسش باز ۹ در `activity.md` است.
### ۴.۸. `SCR-12` — مودال تأیید یا رد تعمیر
```text
┌──────────────────────────────────────────────────────────────┐
│ [۱] │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ [۲] │ │
│ │ [۳] │ │
│ │ ┌────────────────────────────────────────────────────┐ │ │
│ │ │ [۴] │ │ │
│ │ └────────────────────────────────────────────────────┘ │ │
│ │ [۵] │ │
│ │ [۶] [۷] │ │
│ └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
```
| # | عنصر | نوع | محتوا | رفتار | مرجع |
|---|---|---|---|---|---|
| ۱ | پوشش پس‌زمینه | لایه | — | کلیک بیرون: بستن مودال | — |
| ۲ | عنوان مودال | تیتر | «تأیید یا رد تعمیر» | — | `US-05` |
| ۳ | نتیجهٔ تعمیر | متن | توضیحات ثبت‌شده | — | `FR-12` |
| ۴ | دلیل رد | ناحیهٔ متنی | فقط اگر «رد» انتخاب شود | اجباری در حالت رد | `US-05.feature` |
| ۵ | ناحیهٔ خطا | پیام | — | «ذکر دلیل رد الزامی است» | `US-05.feature` |
| ۶ | دکمهٔ تأیید | دکمهٔ اصلی | «تأیید تکمیل تعمیر» | بستن گزارش | `FR-14` |
| ۷ | دکمهٔ رد | دکمهٔ خطر | «رد تعمیر» | ثبت رد + پیگیری | `US-05.feature` |
**حالت‌های خطا:**
| حالت | پیام | رفتار | مرجع |
|---|---|---|---|
| رد بدون دلیل | «ذکر دلیل رد الزامی است» | وضعیت بدون تغییر می‌ماند | `US-05.feature` |
| کاربر غیرمجاز | «دسترسی مجاز نیست» | وضعیت بدون تغییر | `US-05.feature` |
| وضعیت نامناسب | «این گزارش در وضعیت قابل تأیید نیست» | عملیات انجام نمی‌شود | `US-05.feature` |
| کلیک دوباره | — | فقط یک تغییر وضعیت و یک ورودی تاریخچه | `US-05.feature` |
## ۵. اجزای مشترک (Component Inventory)
| شناسه | جزء | توضیح | استفاده در | مرجع |
|---|---|---|---|---|
| `CMP-01` | بج وضعیت | نمایش `label_fa` با رنگ متناظر | `SCR-02`، `SCR-04`، `SCR-05`، `SCR-06`، `SCR-07` | `FR-11` |
| `CMP-02` | بج اولویت | نمایش `label_fa` با رنگ متناظر | `SCR-05`، `SCR-06`، `SCR-07` | `FR-07` |
| `CMP-03` | جدول داده | ستون‌بندی، مرتب‌سازی، صفحه‌بندی | `SCR-02`، `SCR-05`، `SCR-07` | `NFR-04` |
| `CMP-04` | فیلد فرم با اعتبارسنجی | برچسب + نشان اجباری + پیام خطای درجا | `SCR-01`، `SCR-03`، `SCR-12` | `US-01.feature` |
| `CMP-05` | تایم‌لاین تاریخچه | فهرست رویدادهای `report_history` | `SCR-04`، `SCR-06`، `SCR-08` | `FR-16` |
| `CMP-06` | آپلود تصویر | انتخاب و پیش‌نمایش تصویر | `SCR-04` | `FR-04` |
| `CMP-07` | زنگ اعلان | شمارندهٔ خوانده‌نشده + لینک به `SCR-10` | همهٔ صفحات داخلی | `US-16` |
| `CMP-08` | نوار پیام | پیام موفقیت/خطای سطح صفحه | همهٔ صفحات | `NFR-03` |
| `CMP-09` | منوی نقش‌محور | آیتم‌های منو بر اساس نقش | همهٔ صفحات داخلی | `FR-02` |
| `CMP-10` | کادر تأیید | برای اقدام‌های برگشت‌ناپذیر (بستن گزارش) | `SCR-12` | `US-05` |
## ۶. قرارداد رنگی (پیشنهادی)
> رنگ‌ها **پیشنهادی** هستند و باید با پرسش باز ۲۴ تأیید شوند.
| وضعیت / اولویت | رنگ پیشنهادی | توضیح |
|---|---|---|
| ثبت‌شده | خاکستری | تازه ثبت شده، هنوز بررسی نشده |
| ارجاع‌شده | آبی | در انتظار شروع تعمیر |
| در حال تعمیر | نارنجی | در جریان |
| تعمیر انجام‌شده | سبز روشن | در انتظار بازخورد گزارش‌دهنده |
| بسته‌شده | سبز تیره | پایان یافته |
| اولویت کم | خاکستری | — |
| اولویت متوسط | آبی | — |
| اولویت زیاد | نارنجی | — |
| اولویت فوری | قرمز | باید در داشبورد برجسته شود (`US-17`) |
> **الزام دسترس‌پذیری:** رنگ نباید تنها حامل معنا باشد؛ متن برچسب همیشه در کنار رنگ نمایش داده می‌شود.
## ۷. پیام‌های استاندارد رابط کاربری
این جدول، **متن دقیق** پیام‌ها را از فایل‌های Feature استخراج کرده تا در پیاده‌سازی، متن تغییر نکند:
| شناسه | متن پیام | شرایط | مرجع |
|---|---|---|---|
| `MSG-01` | «این فیلد الزامی است» | فیلد اجباری خالی | `US-01.feature`، `US-15.feature` |
| `MSG-02` | «حداکثر طول عنوان ۱۵۰ کاراکتر است» | عنوان بیش از ۱۵۰ کاراکتر | `US-01.feature` |
| `MSG-03` | «خطا در ثبت گزارش؛ لطفاً دوباره تلاش کنید» | خطای سرور در ذخیره | `US-01.feature` |
| `MSG-04` | «نام کاربری یا رمز عبور اشتباه است» | اعتبارنامهٔ نامعتبر | `US-15.feature` |
| `MSG-05` | «خطا در ورود؛ لطفاً بعداً تلاش کنید» | سرویس احراز هویت در دسترس نیست | `US-15.feature` |
| `MSG-06` | «دسترسی مجاز نیست» | تلاش برای دسترسی غیرمجاز | `US-15.feature`، `US-05.feature` |
| `MSG-07` | «ذکر دلیل رد الزامی است» | رد تعمیر بدون دلیل | `US-05.feature` |
| `MSG-08` | «این گزارش در وضعیت قابل تأیید نیست» | تأیید در وضعیت نامناسب | `US-05.feature` |
## ۸. نکات و پرسش‌های باز
| # | پرسش | اثر |
|---|---|---|
| ۲۳ | فناوری و فریم‌ورک رابط کاربری چیست؟ | تعیین روش پیاده‌سازی همهٔ صفحات |
| ۲۴ | پالت رنگی و هویت بصری دانشگاه چیست؟ | بخش ۶ موقت است |
| ۲۵ | آیا رابط کاربری باید واکنش‌گرا (موبایل) باشد؟ | در `NFR-03` صریح نیست؛ بر چیدمان جدول‌ها اثر دارد |
| ۲۶ | سطح دسترسی دقیق مدیر (پرسش باز ۹ در `activity.md`) چیست؟ | تعیین آیتم‌های منوی مدیر |
| ۲۷ | آیا گزارش‌دهنده می‌تواند در هر زمان اطلاعات تکمیلی اضافه کند یا فقط پس از درخواست؟ | رفتار دکمهٔ «افزودن اطلاعات» در `SCR-04` |
| ۲۸ | کانال اعلان (پرسش باز ۸) چیست؟ | محتوای `SCR-10` و `CMP-07` |
| ۲۹ | آیا صفحهٔ «پروفایل کاربر» یا «تغییر رمز» لازم است؟ | در مستندات نیامده |
| ۳۰ | آیا گزارش‌دهنده می‌تواند گزارش خود را ویرایش یا لغو کند؟ | در مستندات نیامده |
> **پرسش ۲۷ مهم است:** `AD-02` این را به‌عنوان نکتهٔ مدل‌سازی علامت زده و `US-04` زمان آن را محدود نکرده است. تا تصمیم‌گیری، رابط کاربری دکمهٔ «افزودن اطلاعات» را فقط پس از درخواست نمایش می‌دهد (محافظه‌کارانه‌ترین حالت).
---
**وضعیت سند:** نسخه اولیه (Draft) – آماده بازبینی
+167 -131
View File
@@ -1,131 +1,167 @@
# داستان‌های کاربر (User Stories) – سامانه مدیریت و گزارش خرابی دانشگاهی
**تهیه‌کننده:** امیرحسن عارف اصل
**بازبین:** ارشیا همتی‌زاده
**آخرین به‌روزرسانی:** ۱۴۰۴/۰۸/۰۴
---
## مقدمه
در این سند، نیازمندی‌های اصلی سامانه به صورت **داستان کاربر (User Story)** نوشته شده‌اند.
هر داستان کاربر از دیدگاه یک نقش مشخص بیان می‌شود و هدف آن را نیز مشخص می‌کند.
قالب استاندارد:
> به عنوان یک **<نقش>**
> می‌خواهم **<هدف>**
> تا بتوانم **<مزیت / نتیجه>**
---
## داستان‌های کاربر مرتبط با گزارش‌دهنده (دانشجو / استاد)
### US-01
به عنوان یک **دانشجو**
می‌خواهم **خرابی مشاهده‌شده را به همراه مکان و توضیحات ثبت کنم**
تا بتوانم **مشکل را سریع به بخش تأسیسات اطلاع دهم و پیگیری کنم**.
### US-02
به عنوان یک **استاد**
می‌خواهم **خرابی کلاس یا آزمایشگاه را ثبت کنم**
تا بتوانم **بدون اتلاف وقت، مشکل را به مسئولان مربوطه اعلام کنم**.
### US-03
به عنوان یک **دانشجو یا استاد**
می‌خواهم **وضعیت گزارش‌هایی که خودم ثبت کرده‌ام را مشاهده کنم**
تا بتوانم **از پیشرفت رسیدگی به گزارشم مطلع شوم**.
### US-04
به عنوان یک **دانشجو یا استاد**
می‌خواهم **تصویر یا توضیح بیشتری به گزارش قبلی اضافه کنم**
تا بتوانم **اطلاعات کامل‌تری در اختیار تعمیرکار قرار دهم**.
### US-05
به عنوان یک **دانشجو یا استاد**
می‌خواهم **پس از اعلام رفع خرابی، آن را تأیید یا رد کنم**
تا بتوانم **از بسته شدن صحیح گزارش مطمئن شوم**.
---
## داستان‌های کاربر مرتبط با کارمند تأسیسات
### US-06
به عنوان یک **کارمند تأسیسات**
می‌خواهم **لیست تمام گزارش‌های باز را مشاهده و فیلتر کنم**
تا بتوانم **گزارش‌های مهم و فوری را سریع‌تر پیدا کنم**.
### US-07
به عنوان یک **کارمند تأسیسات**
می‌خواهم **اولویت هر گزارش را تعیین کنم**
تا بتوانم **تعمیرات را بر اساس اهمیت و فوریت مدیریت کنم**.
### US-08
به عنوان یک **کارمند تأسیسات**
می‌خواهم **یک گزارش را به تعمیرکار مناسب تخصیص دهم**
تا بتوانم **کار را به فرد درست ارجاع دهم و پیگیری کنم**.
### US-09
به عنوان یک **کارمند تأسیسات**
می‌خواهم **وضعیت گزارش را تغییر دهم**
تا بتوانم **وضعیت واقعی رسیدگی به هر گزارش را در سیستم منعکس کنم**.
### US-10
به عنوان یک **کارمند تأسیسات**
می‌خواهم **تاریخچه کامل اقدامات انجام‌شده روی یک گزارش را ببینم**
تا بتوانم **روند رسیدگی را بررسی و در صورت نیاز پیگیری کنم**.
---
## داستان‌های کاربر مرتبط با تعمیرکار
### US-11
به عنوان یک **تعمیرکار**
می‌خواهم **لیست کارهای تخصیص‌یافته به خودم را ببینم**
تا بتوانم **بدانم چه کارهایی در انتظار انجام است**.
### US-12
به عنوان یک **تعمیرکار**
می‌خواهم **شروع کار روی یک گزارش را اعلام کنم**
تا بتوانم **وضعیت گزارش را به «در حال تعمیر» تغییر دهم**.
### US-13
به عنوان یک **تعمیرکار**
می‌خواهم **نتیجه تعمیر را همراه با توضیحات ثبت کنم**
تا بتوانم **گزارش را به مرحله بعدی (تأیید یا پیگیری) برسانم**.
### US-14
به عنوان یک **تعمیرکار**
می‌خواهم **در صورت نیاز، اطلاعات بیشتری از گزارش‌دهنده درخواست کنم**
تا بتوانم **تعمیر را با اطلاعات کامل‌تری انجام دهم**.
---
## داستان‌های کاربر مشترک / سیستمی
### US-15
به عنوان یک **کاربر سیستم**
می‌خواهم **با نام کاربری و رمز عبور وارد سامانه شوم**
تا بتوانم **به امکانات مربوط به نقش خودم دسترسی داشته باشم**.
### US-16
به عنوان یک **کاربر سیستم**
می‌خواهم **هنگام تغییر وضعیت گزارش مرتبط با خودم، اعلان دریافت کنم**
تا بتوانم **از آخرین وضعیت مطلع شوم**.
### US-17
به عنوان یک **کارمند تأسیسات یا مدیر**
می‌خواهم **داشبورد خلاصه‌ای از تعداد گزارش‌های باز و فوری ببینم**
تا بتوانم **وضعیت کلی خرابی‌ها را سریع ارزیابی کنم**.
---
## نکات و کارهای باقی‌مانده
- این داستان‌ها نسخه اولیه هستند و ممکن است در بازبینی تغییر کنند یا داستان‌های جدید اضافه شود.
- جزئیات پذیرش (Acceptance Criteria) برای داستان‌های مهم‌تر در مراحل بعدی نوشته خواهد شد.
- ابهام دامنه (آیا خوابگاه‌ها و فضاهای اداری هم شامل می‌شوند؟) هنوز وجود دارد و روی برخی داستان‌ها تأثیر می‌گذارد.
---
**وضعیت سند:** نسخه اولیه (Draft) – آماده بازبینی
# داستان‌های کاربر (User Stories) – سامانه مدیریت و گزارش خرابی دانشگاهی
**تهیه‌کننده:** امیرحسن عارف اصل
**بازبین:** ارشیا همتی‌زاده
**آخرین به‌روزرسانی:** ۱۴۰۵/۰۸/۱۱
---
## مقدمه
در این سند، نیازمندی‌های اصلی سامانه به صورت **داستان کاربر (User Story)** نوشته شده‌اند.
هر داستان کاربر از دیدگاه یک نقش مشخص بیان می‌شود و هدف آن را نیز مشخص می‌کند.
معیارهای پذیرش (Acceptance Criteria) هر داستان در Issue متناظر آن در GitHub ثبت شده‌اند.
قالب استاندارد:
> به عنوان یک **<نقش>**
> می‌خواهم **<هدف>**
> تا بتوانم **<مزیت / نتیجه>**
---
## ۱. داستان‌های کاربر مرتبط با گزارش‌دهنده (دانشجو / استاد)
### US-01
به عنوان یک **دانشجو**
می‌خواهم **خرابی مشاهده‌شده را به همراه مکان و توضیحات ثبت کنم**
تا بتوانم **مشکل را سریع به بخش تأسیسات اطلاع دهم و پیگیری کنم**.
**نیازمندی‌های مرتبط:** FR-03، FR-05
### US-02
به عنوان یک **استاد**
می‌خواهم **خرابی کلاس یا آزمایشگاه را ثبت کنم**
تا بتوانم **بدون اتلاف وقت، مشکل را به مسئولان مربوطه اعلام کنم**.
**نیازمندی‌های مرتبط:** FR-03
### US-03
به عنوان یک **دانشجو یا استاد**
می‌خواهم **وضعیت گزارش‌هایی که خودم ثبت کرده‌ام را مشاهده کنم**
تا بتوانم **از پیشرفت رسیدگی به گزارشم مطلع شوم**.
**نیازمندی‌های مرتبط:** FR-05، FR-16
### US-04
به عنوان یک **دانشجو یا استاد**
می‌خواهم **تصویر یا توضیح بیشتری به گزارش قبلی اضافه کنم**
تا بتوانم **اطلاعات کامل‌تری در اختیار تعمیرکار قرار دهم**.
**نیازمندی‌های مرتبط:** FR-04
### US-05
به عنوان یک **دانشجو یا استاد**
می‌خواهم **پس از اعلام رفع خرابی، آن را تأیید یا رد کنم**
تا بتوانم **از بسته شدن صحیح گزارش مطمئن شوم**.
**نیازمندی‌های مرتبط:** FR-14
---
## ۲. داستان‌های کاربر مرتبط با کارمند تأسیسات
### US-06
به عنوان یک **کارمند تأسیسات**
می‌خواهم **لیست تمام گزارش‌های باز را مشاهده و فیلتر کنم**
تا بتوانم **گزارش‌های مهم و فوری را سریع‌تر پیدا کنم**.
**نیازمندی‌های مرتبط:** FR-06، FR-08
### US-07
به عنوان یک **کارمند تأسیسات**
می‌خواهم **اولویت هر گزارش را تعیین کنم**
تا بتوانم **تعمیرات را بر اساس اهمیت و فوریت مدیریت کنم**.
**نیازمندی‌های مرتبط:** FR-07
### US-08
به عنوان یک **کارمند تأسیسات**
می‌خواهم **یک گزارش را به تعمیرکار مناسب تخصیص دهم**
تا بتوانم **کار را به فرد درست ارجاع دهم و پیگیری کنم**.
**نیازمندی‌های مرتبط:** FR-09
### US-09
به عنوان یک **کارمند تأسیسات**
می‌خواهم **وضعیت گزارش را تغییر دهم**
تا بتوانم **وضعیت واقعی رسیدگی به هر گزارش را در سیستم منعکس کنم**.
**نیازمندی‌های مرتبط:** FR-11
### US-10
به عنوان یک **کارمند تأسیسات**
می‌خواهم **تاریخچه کامل اقدامات انجام‌شده روی یک گزارش را ببینم**
تا بتوانم **روند رسیدگی را بررسی و در صورت نیاز پیگیری کنم**.
**نیازمندی‌های مرتبط:** FR-16
---
## ۳. داستان‌های کاربر مرتبط با تعمیرکار
### US-11
به عنوان یک **تعمیرکار**
می‌خواهم **لیست کارهای تخصیص‌یافته به خودم را ببینم**
تا بتوانم **بدانم چه کارهایی در انتظار انجام است**.
**نیازمندی‌های مرتبط:** FR-10
### US-12
به عنوان یک **تعمیرکار**
می‌خواهم **شروع کار روی یک گزارش را اعلام کنم**
تا بتوانم **وضعیت گزارش را به «در حال تعمیر» تغییر دهم**.
**نیازمندی‌های مرتبط:** FR-11
### US-13
به عنوان یک **تعمیرکار**
می‌خواهم **نتیجه تعمیر را همراه با توضیحات ثبت کنم**
تا بتوانم **گزارش را به مرحله بعدی (تأیید یا پیگیری) برسانم**.
**نیازمندی‌های مرتبط:** FR-12
### US-14
به عنوان یک **تعمیرکار**
می‌خواهم **در صورت نیاز، اطلاعات بیشتری از گزارش‌دهنده درخواست کنم**
تا بتوانم **تعمیر را با اطلاعات کامل‌تری انجام دهم**.
**نیازمندی‌های مرتبط:** FR-13
---
## ۴. داستان‌های کاربر مشترک / سیستمی
### US-15
به عنوان یک **کاربر سیستم**
می‌خواهم **با نام کاربری و رمز عبور وارد سامانه شوم**
تا بتوانم **به امکانات مربوط به نقش خودم دسترسی داشته باشم**.
**نیازمندی‌های مرتبط:** FR-01، FR-02
### US-16
به عنوان یک **کاربر سیستم**
می‌خواهم **هنگام تغییر وضعیت گزارش مرتبط با خودم، اعلان دریافت کنم**
تا بتوانم **از آخرین وضعیت مطلع شوم**.
**نیازمندی‌های مرتبط:** FR-15
### US-17
به عنوان یک **کارمند تأسیسات یا مدیر**
می‌خواهم **داشبورد خلاصه‌ای از تعداد گزارش‌های باز و فوری ببینم**
تا بتوانم **وضعیت کلی خرابی‌ها را سریع ارزیابی کنم**.
**نیازمندی‌های مرتبط:** FR-17
---
## ۵. نکات و پرسش‌های باز
- این داستان‌ها نسخه اولیه هستند و ممکن است در بازبینی تغییر کنند یا داستان‌های جدید اضافه شود.
- معیارهای پذیرش هر داستان در Issue متناظر آن در GitHub ثبت شده‌اند. در مواردی که نیازمندی‌ها هنوز مشخص نیستند، فرض‌های موقت در همان Issue علامت‌گذاری شده‌اند.
- ابهام دامنه (آیا خوابگاه‌ها و فضاهای اداری هم شامل می‌شوند؟) هنوز وجود دارد و روی برخی داستان‌ها تأثیر می‌گذارد.
- پرسش‌های باز دیگر (اولویت‌ها، وضعیت‌ها، اعلان‌ها و ...) در بخش «نکات و پرسش‌های باز» [نمودارهای فعالیت](activity.md) فهرست شده‌اند.
---
**وضعیت سند:** نسخه اولیه (Draft) – آماده بازبینی
+42
View File
@@ -0,0 +1,42 @@
# مرجع: US-01 ، FR-03 ، FR-05 ، AD-02
Feature: ثبت خرابی توسط دانشجو
به عنوان یک دانشجو
می‌خواهم خرابی مشاهده‌شده را به همراه مکان و توضیحات ثبت کنم
تا بتوانم مشکل را سریع به بخش تأسیسات اطلاع دهم و پیگیری کنم
Background:
Given کاربری با نقش "دانشجو" و نام کاربری "student1" وارد سامانه شده است
Scenario: ثبت موفق گزارش خرابی با اطلاعات کامل
When فرم ثبت گزارش را با عنوان "چراغ کلاس ۱۰۲ روشن نمی‌شود"، توضیحات "کلید برق کار نمی‌کند"، محل "ساختمان الف - کلاس ۱۰۲" و نوع تجهیز "روشنایی" ارسال می‌کند
Then گزارش با وضعیت "ثبت‌شده" ذخیره می‌شود
And شناسه یکتای گزارش نمایش داده می‌شود
And گزارش در فهرست "گزارش‌های من" دانشجو دیده می‌شود
Scenario Outline: ارسال فرم با یک فیلد اجباری خالی
When فرم ثبت گزارش را با فیلد "<فیلد>" خالی ارسال می‌کند
Then پیام خطای "این فیلد الزامی است" کنار "<فیلد>" نمایش داده می‌شود
And هیچ گزارشی ذخیره نمی‌شود
Examples:
| فیلد |
| عنوان |
| توضیحات |
| محل خرابی |
| نوع تجهیز |
Scenario: عنوان با طول مرزی ۱۵۰ کاراکتر پذیرفته می‌شود
When فرم ثبت گزارش را با عنوانی به طول ۱۵۰ کاراکتر و سایر فیلدهای معتبر ارسال می‌کند
Then گزارش با وضعیت "ثبت‌شده" ذخیره می‌شود
Scenario: عنوان با ۱۵۱ کاراکتر رد می‌شود
When فرم ثبت گزارش را با عنوانی به طول ۱۵۱ کاراکتر و سایر فیلدهای معتبر ارسال می‌کند
Then پیام خطای "حداکثر طول عنوان ۱۵۰ کاراکتر است" نمایش داده می‌شود
And هیچ گزارشی ذخیره نمی‌شود
Scenario: خطای سرور هنگام ذخیره‌سازی
Given سرویس ذخیره‌سازی در دسترس نیست
When فرم ثبت گزارش را با اطلاعات معتبر ارسال می‌کند
Then پیام "خطا در ثبت گزارش؛ لطفاً دوباره تلاش کنید" نمایش داده می‌شود
And مقادیر واردشده در فرم حفظ می‌شوند
And هیچ گزارش ناقصی ذخیره نمی‌شود
+51
View File
@@ -0,0 +1,51 @@
# مرجع: US-05 ، FR-14 ، AD-05
Feature: تأیید یا رد نتیجه تعمیر توسط گزارش‌دهنده
به عنوان یک دانشجو یا استاد
می‌خواهم پس از اعلام رفع خرابی، آن را تأیید یا رد کنم
تا بتوانم از بسته شدن صحیح گزارش مطمئن شوم
Background:
Given گزارش شماره "R-100" با وضعیت "تعمیر انجام‌شده" و گزارش‌دهنده "student1" وجود دارد
Scenario: تأیید نتیجه تعمیر توسط گزارش‌دهنده
Given کاربر "student1" وارد سامانه شده است
When نتیجه تعمیر گزارش "R-100" را تأیید می‌کند
Then وضعیت گزارش "R-100" به "بسته‌شده" تغییر می‌کند
And تاریخچه گزارش ثبت تأیید گزارش‌دهنده را نشان می‌دهد
Scenario: رد نتیجه تعمیر بدون ذکر دلیل
Given کاربر "student1" وارد سامانه شده است
When نتیجه تعمیر گزارش "R-100" را با دلیل خالی رد می‌کند
Then پیام خطای "ذکر دلیل رد الزامی است" نمایش داده می‌شود
And وضعیت گزارش "R-100" بدون تغییر "تعمیر انجام‌شده" می‌ماند
Scenario: رد نتیجه تعمیر با ذکر دلیل
Given کاربر "student1" وارد سامانه شده است
When نتیجه تعمیر گزارش "R-100" را با دلیل "خرابی هنوز برطرف نشده است" رد می‌کند
Then دلیل رد در تاریخچه گزارش ثبت می‌شود
And گزارش برای پیگیری بیشتر علامت‌گذاری می‌شود
Scenario: کاربر دیگری نمی‌تواند نتیجه تعمیر را تأیید کند
Given کاربر "student2" وارد سامانه شده است
When سعی می‌کند نتیجه تعمیر گزارش "R-100" را تأیید کند
Then پیام "دسترسی مجاز نیست" نمایش داده می‌شود
And وضعیت گزارش "R-100" بدون تغییر "تعمیر انجام‌شده" می‌ماند
Scenario Outline: تأیید یا رد فقط در وضعیت "تعمیر انجام‌شده" مجاز است
Given گزارش "R-101" با وضعیت "<وضعیت>" وجود دارد
When کاربر "student1" سعی می‌کند نتیجه تعمیر گزارش "R-101" را تأیید کند
Then عملیات انجام نمی‌شود
And پیام "این گزارش در وضعیت قابل تأیید نیست" نمایش داده می‌شود
Examples:
| وضعیت |
| ثبت‌شده |
| ارجاع‌شده |
| در حال تعمیر |
| بسته‌شده |
Scenario: کلیک دوباره روی تأیید یک تغییر وضعیت بیشتر ایجاد نمی‌کند
Given کاربر "student1" وارد سامانه شده است
When دو بار پشت سر هم روی دکمه تأیید کلیک می‌کند
Then وضعیت گزارش "R-100" فقط یک بار به "بسته‌شده" تغییر می‌کند
And تاریخچه گزارش فقط یک ورودی تأیید دارد
+47
View File
@@ -0,0 +1,47 @@
# مرجع: US-15 ، FR-01 ، FR-02 ، AD-01
Feature: ورود به سامانه
به عنوان یک کاربر سیستم
می‌خواهم با نام کاربری و رمز عبور وارد سامانه شوم
تا بتوانم به امکانات مربوط به نقش خودم دسترسی داشته باشم
Scenario: ورود موفق و انتقال به داشبورد نقش کاربر
Given کاربری با نام کاربری "student1" و رمز عبور معتبر وجود دارد
When نام کاربری "student1" و رمز عبور معتبر را وارد و فرم را ارسال می‌کند
Then کاربر وارد سامانه می‌شود
And صفحه ثبت گزارش خرابی برای نقش "دانشجو" نمایش داده می‌شود
Scenario: رمز عبور اشتباه
Given کاربری با نام کاربری "student1" وجود دارد
When نام کاربری "student1" و رمز عبور "اشتباه" را وارد می‌کند
Then پیام "نام کاربری یا رمز عبور اشتباه است" نمایش داده می‌شود
And پیام مشخص نمی‌کند کدام فیلد اشتباه است
And نام کاربری "student1" در فرم باقی می‌ماند
And کاربر وارد سامانه نمی‌شود
Scenario Outline: ارسال فرم ورود با فیلد خالی
When فرم ورود را با "<فیلد خالی>" خالی ارسال می‌کند
Then ورود انجام نمی‌شود
And پیام "این فیلد الزامی است" کنار "<فیلد خالی>" نمایش داده می‌شود
Examples:
| فیلد خالی |
| نام کاربری |
| رمز عبور |
Scenario: دسترسی به صفحه نقش دیگر مجاز نیست
Given کاربر "student1" با نقش "دانشجو" وارد سامانه شده است
When آدرس صفحه داشبورد کارمند تأسیسات را مستقیم باز می‌کند
Then پیام "دسترسی مجاز نیست" نمایش داده می‌شود
And هیچ اطلاعات گزارش مدیریتی نمایش داده نمی‌شود
Scenario: خروج از سامانه و محافظت از صفحات
Given کاربر "student1" وارد سامانه شده است
When از سامانه خارج می‌شود
And سپس آدرس صفحه ثبت گزارش را باز می‌کند
Then کاربر به صفحه ورود هدایت می‌شود
Scenario: سرویس احراز هویت در دسترس نیست
Given سرویس احراز هویت در دسترس نیست
When نام کاربری و رمز عبور معتبر را ارسال می‌کند
Then پیام "خطا در ورود؛ لطفاً بعداً تلاش کنید" نمایش داده می‌شود
And کاربر وارد سامانه نمی‌شود