Files
ERP/pm/API_CONTRACT.md
MMD 2747f9d4bb chore(pm): vendor the Aramesh/PM platform under pm/ (squash of Aramesh/PM @ 91f3271)
The PM panel (PmPanelPage -> iframe /pm/) needs the project-management
platform served at /pm/ on the ERP domain. Source: org repo Aramesh/PM,
branch feature/project-management-platform. Update via:
git subtree pull --prefix=pm aramesh-pm feature/project-management-platform --squash
2026-10-07 15:14:20 +03:30

103 lines
6.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PM API Contract (v3) — Standalone Native Platform — پایه: /api/v1
پلتفرم مدیریت پروژه ساختمانی بومی (Standalone)، مستقل و بدون وابستگی به هیچ سیستم خارجی.
## Auth
- `POST /auth/login` `{username, password}` → `{data:{token, user:{id, username, display_name, role}}}`
- `GET /auth/dev-roles` (در حالت توسعه) → لیست نقش‌های آماده جهت ورود سریع
- `POST /auth/dev-login` `{role}` (در حالت توسعه) → دریافت سریع توکن نقش انتخابی
- همه endpointها (جز لاگین و فایل‌های عمومی) هدر `Authorization: Bearer <token>` می‌خواهند.
- خطاها: `{"error": {"code", "message", "field"?}}` — کدها: `VALIDATION_ERROR` (400)،
`UNAUTHORIZED` (401)، `FORBIDDEN` (403)، `NOT_FOUND` (404)، `CONFLICT` (409)،
`UPSTREAM_UNAVAILABLE` (503).
## تاریخ جلالی
- **همه تاریخ‌های قابل مشاهده در UI شمسی‌اند.** API هم ISO می‌پذیرد/می‌دهد و هم شمسی.
- هر تسک علاوه بر `start_date`/`due_date` (ISO) فیلدهای `start_date_jalali`/
`due_date_jalali` را هم برمی‌گرداند («1405/06/23»).
- `PATCH /tasks/{id}/dates` هر دو قالب را می‌پذیرد: `1405/06/23` یا `2026-09-14`
(سال ≥ 1700 میلادی، کمتر از آن شمسی تفسیر می‌شود). روز نامعتبر → 400.
- تبدیل‌ها در `backend/app/utils/jalali.py` و `frontend/src/lib/jalali.ts` انجام می‌شوند.
## Dashboard
- `GET /dashboard/today` → `{data:{summary:{problems,warnings,ok}, sections:{overdue,due_today,awaiting_qc,failed_qc,blocked,upcoming}}}`
- `awaiting_qc` = وضعیت‌های `pre_qc_pending|exec_qc_pending|ready`
- `failed_qc` = وضعیت‌های `pre_qc_failed|qc_failed_rework`
## Projects
- `GET /projects` → `[...{id, name, identifier, description, active, erp_project_id, created_at, stats:{total, awaiting_qc, failed_qc, overdue}}]`
- `POST /projects` → ساخت پروژه جدید
- `GET /projects/{id}` → جزئیات پروژه به همراه آمارهای تسک‌ها
- `PUT /projects/{id}` | `DELETE /projects/{id}`
- `GET /projects/{id}/gantt` → داده‌های گانت چارت پروژه
- `PATCH /projects/{id}/erp-mapping {erp_project_id}`
## Tasks
- `GET /tasks?project_id=&search=&qc_status=&status=&page=&page_size=`
- `POST /tasks` → ثبت فعالیت/تسک جدید
- `GET /tasks/{id}` → تسک + `relations` + `children` + **`qc`** + **`qc_definitions`** + `defects` + `open_defects`
- `PUT /tasks/{id}` → ویرایش اطلاعات تسک
- `DELETE /tasks/{id}` → حذف تسک
- `PATCH /tasks/{id}/progress {percentage: 0..100}`
- **قاعده ۱:** اگر `percentage > 0` و بازرسی پیش از اجرا تأیید نشده باشد → 400
«بازرسی پیش از اجرا تأیید نشده است (N سؤال باقی‌مانده)»
- **قاعده ۲:** اگر `percentage >= 100` و هر سؤال الزامی تأییدنشده/مردود باشد → 400
«تا زمانی که همه بازرسی‌های الزامی تأیید نشوند پیشرفت ۱۰۰٪ مجاز نیست (…)»
- `PATCH /tasks/{id}/dates {start_date?, due_date?}` (ISO یا شمسی)
- `POST /tasks/relations` | `DELETE /tasks/relations/{id}` → مدیریت روابط وابستگی تسک‌ها (FS, SS, FF, SF)
### شکل بلوک `qc` در جزئیات تسک
```json
{"pre": {"total":3,"passed":3,"failed":0,"pending":0,"na":0,"required_unresolved":0,"status":"passed"},
"exec": {"total":6,"passed":2,"failed":1,"pending":3,"na":0,"required_unresolved":4,"status":"pending"},
"all": { /* مجموع */ },
"status": "exec_qc_pending",
"can_start": true, "can_complete": false,
"block_reasons": ["تا زمانی که همه بازرسی‌های الزامی تأیید نشوند پیشرفت ۱۰۰٪ مجاز نیست (۴ سؤال باقی‌مانده، ۱ مورد مردود)"]}
```
### وضعیت‌های `qc_status` روی تسک
`none` · `pre_qc_pending` · `pre_qc_failed` · `ready` · `exec_qc_pending` ·
`in_progress` · `qc_failed_rework` · `final_passed`
## QC — تعریف (Definition)
### قالب‌های سراسری (قابل استفاده مجدد)
- `GET /qc/templates` → `[{id,name,activity_type,description,questions:[{id,phase,text,sort_order,required}]}]`
- `POST /qc/templates {name, activity_type?, description?, questions?:[…]}` → `{data:{id}}`
- `PATCH /qc/templates/{id} {name?,activity_type?,description?}`
- `DELETE /qc/templates/{id}`
- `POST /qc/templates/{id}/questions {phase,text,required?,sort_order?}`
- `PATCH /qc/questions/{qid} {text?,phase?,required?,sort_order?}`
- `DELETE /qc/questions/{qid}`
- `PUT /qc/templates/{id}/questions {questions:[…]}` — جایگزینی گروهی (برای ادیتور)
`phase` ∈ `"pre"` (پیش از اجرا) · `"during"` (هنگام اجرا) · `"after"` (پس از اجرا)
### تعریف مخصوص تسک (کپی مستقل — ویرایش آن قالب سراسری را تغییر نمی‌دهد)
- `GET /qc/tasks/{task_id}` → `{data:{task, definitions:[{id,name,source_template_id,created_at,questions:[{…,result,history_count}],summary}], readiness}}`
- `POST /qc/tasks/{task_id}/definition {name?, template_id?}` → **کپی عمیق** سؤالات قالب
- `PATCH /qc/definitions/{id} {name}` | `DELETE /qc/definitions/{id}`
- `POST /qc/definitions/{id}/questions {text,phase,required?,sort_order?}`
- `PATCH /qc/task-questions/{qid} {text?,phase?,required?,sort_order?}`
- `DELETE /qc/task-questions/{qid}`
## QC — اجرا (Execution)
- `PUT /qc/task-questions/{qid}/result {answer:"pass"|"fail"|"na", comment?}`
→ `{data:{question_id, answer, task_qc_status, readiness}}`
- پاسخ‌ها **append-only** هستند (تاریخچه می‌ماند؛ بازرسی مجدد پس از رفع عیب ممکن است)
- تعریف و اجرا کاملاً جدا هستند: هنگام ساخت/کپی سؤال هیچ پاس/ردی ثبت نمی‌شود.
- عیب‌ها:
- `POST /qc/defects {task_id, question_id?, title, description?, severity?, corrective_action?, photo_id?}`
- `POST /qc/defects/{id}/resolve {resolution_notes?}`
- عکس عیب: `POST /files` (multipart) → `{data:{id, url}}` سپس `photo_id`
## فایل‌ها
- `POST /files` multipart (jpg/png/webp تا ۱۰MB) → `{data:{id,url,filename}}`
- `GET /files/{id}`
## Materials / Resources (یکپارچگی ERP)
- `GET/POST /tasks/{task_id}/materials` · `PATCH/DELETE /materials/{req_id}`
- `GET /erp/materials?search=` · `GET /erp/projects`
- `POST /materials/{req_id}/reserve|purchase-request` · `GET /reservations` · `POST /reservations/{id}/release`
- `GET/PATCH /purchase-requests` · `POST /projects/{project_id}/erp-mapping`