Task #62: Service Orders backend foundation (corrected)

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.
This commit is contained in:
riyadhafraa
2026-04-21 18:34:14 +00:00
parent cdf5bf4d33
commit 2602edaca0
9 changed files with 361 additions and 391 deletions
+4 -4
View File
@@ -37,7 +37,7 @@ async function main() {
{ name: "services:manage", descriptionAr: "إدارة الخدمات", descriptionEn: "Manage Services" },
{ name: "users:manage", descriptionAr: "إدارة المستخدمين", descriptionEn: "Manage Users" },
{ name: "chat:access", descriptionAr: "الوصول للمحادثات", descriptionEn: "Access Chat" },
{ name: "orders:receive", descriptionAr: "استقبال الطلبات", descriptionEn: "Receive Service Orders" },
{ name: "orders.receive", descriptionAr: "استلام الطلبات", descriptionEn: "Receive service orders" },
];
await db.insert(permissionsTable).values(permissions).onConflictDoNothing();
@@ -50,8 +50,8 @@ async function main() {
.insert(rolesTable)
.values({
name: "order_receiver",
descriptionAr: "مستقبل الطلبات",
descriptionEn: "Service Order Receiver",
descriptionAr: "مستلم الطلبات",
descriptionEn: "Order Receiver",
})
.onConflictDoNothing()
.returning();
@@ -83,7 +83,7 @@ async function main() {
// Assign orders:receive permission to order_receiver role
if (orderReceiverResolved && allInsertedPerms.length > 0) {
const ordersPerm = allInsertedPerms.find((p) => p.name === "orders:receive");
const ordersPerm = allInsertedPerms.find((p) => p.name === "orders.receive");
if (ordersPerm) {
await db
.insert(rolePermissionsTable)