mirror of
https://github.com/AmirAref/paya-university-fault-system.git
synced 2026-11-12 02:53:34 +00:00
Merge pull request #26 from AmirAref/arshia-tasks
افزودن نمودار کلاس (class-diagram.md) بر اساس مستندات تحلیل
This commit is contained in:
@@ -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) – آماده بازبینی
|
||||||
@@ -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) – آماده بازبینی
|
||||||
@@ -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) – آماده بازبینی
|
||||||
@@ -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) – آماده بازبینی
|
||||||
Reference in New Issue
Block a user