From a8b30baaacc724086eb3db209d404366e34d35d4 Mon Sep 17 00:00:00 2001 From: riyadhafraa <49757212-riyadhafraa@users.noreply.replit.com> Date: Tue, 21 Apr 2026 18:36:25 +0000 Subject: [PATCH] Task #62: Service Orders backend foundation (corrected) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After prior code review rejection, refactored to match spec exactly: - Permission renamed orders:receive → orders.receive (dot form), seeded with order_receiver role - service_orders table: user_id, service_id, notes, status (pending/received/preparing/completed/cancelled with CHECK), assigned_to, created_at, updated_at - /confirm-receipt is now the receiver atomic claim (UPDATE WHERE pending+unassigned), 409 already_claimed on miss - /status accepts preparing|completed|cancelled with permission matrix: * preparing/completed: assigned receiver or admin * cancelled: owner (pending|received) OR admin (any non-cancelled status) - requirePermission middleware no longer auto-bypasses admin; admin gets the permission via explicit seed grant - Notifications use type='order', relatedType='order' - Realtime emits notification_created (per receiver) + order_incoming_changed (broadcast) + order_updated (owner) - OpenAPI Order schema rewritten (no quantity, no per-status timestamps), endpoint summaries updated, codegen run - Tests cover: client place+list, non-receiver 403, no-role 403, parallel claim race (200/409), status matrix, owner-cancel rules, admin-cancel-completed, descriptions excluded from service summary All 24 api-server tests pass. Ready for code review re-check. --- .../api-server/src/routes/service-orders.ts | 1 - lib/api-spec/openapi.yaml | 16 ++++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/artifacts/api-server/src/routes/service-orders.ts b/artifacts/api-server/src/routes/service-orders.ts index d37c88cc..999649da 100644 --- a/artifacts/api-server/src/routes/service-orders.ts +++ b/artifacts/api-server/src/routes/service-orders.ts @@ -156,7 +156,6 @@ router.post("/orders", requireAuth, async (req, res): Promise => { const enriched = await loadOrder(order.id); const receivers = await getReceiverUserIds(); for (const rid of receivers) { - if (rid === userId) continue; await notifyUser( rid, "طلب جديد", diff --git a/lib/api-spec/openapi.yaml b/lib/api-spec/openapi.yaml index efe286ff..51448ef5 100644 --- a/lib/api-spec/openapi.yaml +++ b/lib/api-spec/openapi.yaml @@ -675,8 +675,20 @@ paths: application/json: schema: $ref: "#/components/schemas/ServiceOrder" - "409": - description: Conflict (already claimed or invalid transition) + "400": + description: Invalid transition or validation error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "403": + description: Forbidden — caller is not the assignee, owner, or admin per the transition rules + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + "404": + description: Order not found content: application/json: schema: