{"openapi":"3.0.3","info":{"title":"Miss Leen API","version":"3.0.0","description":"API for the Miss Leen store (miss-leen.com) and the store + factory dashboard (admin.miss-leen.com), served at `https://api.miss-leen.com/api/v1`.\n\n**Envelope.** Every response is `{ success, message, data, meta?, path, timestamp, requestId }`. Errors are `{ success:false, message (Arabic), messageEn, errors? }`; validation errors list `errors: { field: message }`.\n\n**Auth.** Staff: `POST /auth/login` → use `accessToken` as *staffAuth* (Authorize button). Customers: `POST /store/auth/login` → *customerAuth*. Access tokens last 15 minutes; refresh tokens rotate (`/auth/refresh`, `/store/auth/refresh`).\n\n**Permissions.** Staff endpoints list the permission they need; a missing one returns 403. See `GET /permissions` for the catalog.\n\n**Conventions.** Store money is whole EGP. Bilingual text is `{ en, ar }`. Factory endpoints keep their original snake_case fields."},"servers":[{"url":"/api/v1","description":"This server"}],"tags":[{"name":"Auth","description":"Staff sign-in. Access tokens last 15 minutes; refresh tokens rotate on every use (reusing an old one signs the account out everywhere)."},{"name":"Roles & permissions","description":"Permission catalog and roles. Super Admin is locked and holds every permission."},{"name":"Staff","description":"Dashboard / factory staff accounts. You can't grant permissions you don't hold; the last active Super Admin stays; `root` only changes its own password."},{"name":"Uploads","description":"Images are checked, auto-rotated, resized and re-encoded to WebP (metadata stripped)."},{"name":"Storefront","description":"Public store API used by miss-leen.com. Prices and stock are always recomputed on the server."},{"name":"Customer accounts","description":"Store customer sign-up / sign-in, profile, addresses, wishlist. Use the customer access token."},{"name":"Products","description":"Dashboard catalog. Product codes and blank SKUs are generated by the server."},{"name":"Categories & types","description":"Categories (sizes + size guide) and pajama types (styles)."},{"name":"Inventory","description":"Variant stock and the stock-movement log."},{"name":"Banners & coupons","description":"Home banners, the announcement bar and discount codes."},{"name":"Orders & customers","description":"Fulfilment workflow: pending → confirmed → processing → ready → shipped → out → delivered (cancel / return restock)."},{"name":"Reports","description":"Dashboard overview and sidebar counts."},{"name":"Tasks","description":"Team tasks. Managers (`tasks.assign`) see and assign everything; others work on their own tasks."},{"name":"Notifications","description":"In-app staff notifications (by user or by permission)."},{"name":"Settings","description":"Store settings: payment details, methods, delivery fees, low-stock threshold, Mama & Mini pairs."},{"name":"Activity log","description":"Every dashboard change: who, what, when."},{"name":"Factory · Employees","description":"Factory employees. Factory endpoints keep the v2 snake_case JSON; their error messages are Arabic strings."},{"name":"Factory · Attendance","description":"Daily attendance; partial absence = status absent + day_fraction < 1. Factory endpoints keep the v2 snake_case JSON; their error messages are Arabic strings."},{"name":"Factory · Salaries","description":"Monthly salary records: net = daily×26 + Fridays − absences + extra hours − errands×30 − early-leave hours − cash advance. Factory endpoints keep the v2 snake_case JSON; their error messages are Arabic strings."},{"name":"Factory · Cash advances","description":"Advances; every change recalculates that month's salary record. Factory endpoints keep the v2 snake_case JSON; their error messages are Arabic strings."},{"name":"Factory · Leaves (استئذان)","description":"Errands (flat 30 EGP) and early leave (hours × hourly rate); every change recalculates that month's salary record. Factory endpoints keep the v2 snake_case JSON; their error messages are Arabic strings."},{"name":"Factory · Ledger","description":"Debtors & creditors. Balance = debits − payments; a payment can’t exceed the balance. Factory endpoints keep the v2 snake_case JSON; their error messages are Arabic strings."},{"name":"System","description":"Health check (outside /api/v1)."}],"x-tagGroups":[{"name":"Platform","tags":["Auth","Roles & permissions","Staff","Uploads"]},{"name":"Store","tags":["Storefront","Customer accounts"]},{"name":"Dashboard","tags":["Products","Categories & types","Inventory","Banners & coupons","Orders & customers","Reports","Tasks","Notifications","Settings","Activity log"]},{"name":"Factory","tags":["Factory · Employees","Factory · Attendance","Factory · Salaries","Factory · Cash advances","Factory · Leaves (استئذان)","Factory · Ledger"]},{"name":"System","tags":["System"]}],"paths":{"/auth/login":{"post":{"tags":["Auth"],"summary":"Sign in (username or email)","operationId":"postAuthLogin","security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"allOf":[{"$ref":"#/components/schemas/Tokens"},{"type":"object","properties":{"user":{"$ref":"#/components/schemas/StaffProfile"}}}]}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"identifier":{"type":"string","example":"admin"},"password":{"type":"string","format":"password"}},"required":["identifier","password"]}}}}}},"/auth/refresh":{"post":{"tags":["Auth"],"summary":"Rotate the refresh token","description":"Returns a new access + refresh token. The old refresh token stops working.","operationId":"postAuthRefresh","security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Tokens"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"refreshToken":{"type":"string"}},"required":["refreshToken"]}}}}}},"/auth/logout":{"post":{"tags":["Auth"],"summary":"Sign out this device","operationId":"postAuthLogout","security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"refreshToken":{"type":"string"}}}}}}}},"/auth/logout/all":{"post":{"tags":["Auth"],"summary":"Sign out every device","operationId":"postAuthLogoutAll","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/me":{"get":{"tags":["Auth"],"summary":"My profile + effective permissions","operationId":"getAuthMe","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StaffProfile"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/change-password":{"post":{"tags":["Auth"],"summary":"Change my password","description":"Signs out every other session.","operationId":"postAuthChangePassword","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"currentPassword":{"type":"string","format":"password"},"newPassword":{"type":"string","format":"password","minLength":8}},"required":["currentPassword","newPassword"]}}}}}},"/auth/sessions":{"get":{"tags":["Auth"],"summary":"My active sessions","operationId":"getAuthSessions","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Session"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/sessions/{id}":{"delete":{"tags":["Auth"],"summary":"End one of my sessions","operationId":"deleteAuthSessionsId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/permissions":{"get":{"tags":["Roles & permissions"],"summary":"Permission catalog (grouped)","operationId":"getPermissions","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PermissionGroup"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/roles":{"get":{"tags":["Roles & permissions"],"summary":"List roles","description":"**Permission:** `roles.manage` or `admins.manage`","operationId":"getRoles","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Role"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Roles & permissions"],"summary":"Create a role","description":"**Permission:** `roles.manage`","operationId":"postRoles","security":[{"staffAuth":[]}],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Role"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"nameEn":{"type":"string"},"nameAr":{"type":"string"},"descriptionEn":{"type":"string"},"descriptionAr":{"type":"string"},"permissionKeys":{"type":"array","items":{"type":"string"}}},"required":["nameEn"]}}}}}},"/roles/{id}":{"patch":{"tags":["Roles & permissions"],"summary":"Rename / describe / (de)activate a role","description":"**Permission:** `roles.manage`","operationId":"patchRolesId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Role"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"nameEn":{"type":"string"},"nameAr":{"type":"string"},"descriptionEn":{"type":"string"},"descriptionAr":{"type":"string"},"isActive":{"type":"boolean"}}}}}}},"delete":{"tags":["Roles & permissions"],"summary":"Delete a custom role","description":"Built-in roles can only be deactivated; roles in use cannot be deleted.\n\n**Permission:** `roles.manage`","operationId":"deleteRolesId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/roles/{id}/permissions":{"put":{"tags":["Roles & permissions"],"summary":"Replace a role's permissions","description":"**Permission:** `roles.manage`","operationId":"putRolesIdPermissions","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Role"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"permissionKeys":{"type":"array","items":{"type":"string","example":"orders.view"}}},"required":["permissionKeys"]}}}}}},"/users":{"get":{"tags":["Staff"],"summary":"List staff","description":"**Permission:** `admins.manage`","operationId":"getUsers","security":[{"staffAuth":[]}],"parameters":[{"name":"q","in":"query","schema":{"type":"string"}},{"name":"roleId","in":"query","schema":{"type":"integer"}},{"name":"active","in":"query","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StaffUser"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Staff"],"summary":"Create a staff account","description":"**Permission:** `admins.manage`","operationId":"postUsers","security":[{"staffAuth":[]}],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StaffUser"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Username or email already used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"username":{"type":"string","pattern":"^[A-Za-z][A-Za-z0-9._-]{2,29}$"},"password":{"type":"string","minLength":8},"fullName":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"responsibility":{"type":"string"},"roleIds":{"type":"array","items":{"type":"integer"}},"permissions":{"type":"array","items":{"type":"string"}},"isActive":{"type":"boolean","default":true}},"required":["username","password","fullName"]}}}}}},"/users/{id}":{"patch":{"tags":["Staff"],"summary":"Update profile / password / direct permissions / active","description":"**Permission:** `admins.manage`","operationId":"patchUsersId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StaffUser"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fullName":{"type":"string"},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"responsibility":{"type":"string","nullable":true},"password":{"type":"string","minLength":8},"permissions":{"type":"array","items":{"type":"string"}},"isActive":{"type":"boolean"}}}}}}},"delete":{"tags":["Staff"],"summary":"Delete a staff account","description":"**Permission:** `admins.manage`","operationId":"deleteUsersId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/users/{id}/roles":{"put":{"tags":["Staff"],"summary":"Replace a staff member's roles","description":"**Permission:** `admins.manage`","operationId":"putUsersIdRoles","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StaffUser"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"roleIds":{"type":"array","items":{"type":"integer"}}},"required":["roleIds"]}}}}}},"/users/{id}/force-logout":{"post":{"tags":["Staff"],"summary":"Sign a staff member out everywhere","description":"**Permission:** `admins.manage`","operationId":"postUsersIdForceLogout","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/uploads/purposes":{"get":{"tags":["Uploads"],"summary":"What each upload purpose accepts","operationId":"getUploadsPurposes","security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/UploadPurpose"}}}}]}}}}}}},"/uploads":{"post":{"tags":["Uploads"],"summary":"Upload an image","description":"The permission needed depends on `purpose`: PRODUCT_IMAGE → products.create/update, CATEGORY_IMAGE → categories.manage, BANNER_IMAGE → banners.manage, AVATAR → admins.manage, PAYMENT_PROOF → payments.verify.\n\n**Permission:** `products.create` or `products.update` or `categories.manage` or `banners.manage` or `admins.manage` or `payments.verify`","operationId":"postUploads","security":[{"staffAuth":[]}],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Upload"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"purpose":{"type":"string","enum":["PRODUCT_IMAGE","CATEGORY_IMAGE","BANNER_IMAGE","AVATAR","PAYMENT_PROOF"]},"file":{"type":"string","format":"binary"}},"required":["purpose","file"]}}}}},"get":{"tags":["Uploads"],"summary":"List uploads","description":"**Permission:** `uploads.manage`","operationId":"getUploads","security":[{"staffAuth":[]}],"parameters":[{"name":"purpose","in":"query","schema":{"type":"string"}},{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"default":60}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Upload"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/uploads/{id}":{"delete":{"tags":["Uploads"],"summary":"Delete an upload","description":"**Permission:** `uploads.manage`","operationId":"deleteUploadsId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/store/bootstrap":{"get":{"tags":["Storefront"],"summary":"Store settings, governorates, categories, types, live banners, pairs, labels","operationId":"getStoreBootstrap","security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"object","properties":{"settings":{"type":"object","properties":{"freeShip":{"type":"integer"},"methods":{"type":"object","properties":{"cod":{"type":"boolean"},"instapay":{"type":"boolean"},"vfcash":{"type":"boolean"}}},"instapay":{"type":"object","properties":{"handle":{"type":"string"},"name":{"type":"string"}},"nullable":true},"vfcash":{"type":"object","properties":{"number":{"type":"string"},"name":{"type":"string"}},"nullable":true}}},"governorates":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"$ref":"#/components/schemas/Localized"},"fee":{"type":"integer"},"eta":{"type":"string"}}}},"categories":{"type":"array","items":{"$ref":"#/components/schemas/Category"}},"styles":{"type":"array","items":{"$ref":"#/components/schemas/Style"}},"banners":{"type":"object","properties":{"hero":{"type":"array","items":{"$ref":"#/components/schemas/Banner"}},"bar":{"type":"array","items":{"$ref":"#/components/schemas/Banner"}}}},"pairs":{"type":"array","items":{"type":"array","items":{"type":"string","description":"product slug"}}},"labels":{"type":"object"}}}}}]}}}}}}},"/store/products":{"get":{"tags":["Storefront"],"summary":"Visible products (filter + sort)","operationId":"getStoreProducts","security":[],"parameters":[{"name":"cat","in":"query","schema":{"type":"string"},"description":"Category slug, or all | new | sale | best"},{"name":"style","in":"query","schema":{"type":"string"},"description":"Type slug"},{"name":"sizes","in":"query","schema":{"type":"string"},"description":"Comma-separated sizes"},{"name":"min","in":"query","schema":{"type":"integer"}},{"name":"max","in":"query","schema":{"type":"integer"}},{"name":"inStock","in":"query","schema":{"type":"string","enum":["true","false"]}},{"name":"q","in":"query","schema":{"type":"string"},"description":"Search text"},{"name":"sort","in":"query","schema":{"type":"string","enum":["featured","newest","price_asc","price_desc","popular","discount"]}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"default":500}}],"responses":{"200":{"description":"OK — `meta.total` = matches before the limit","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Product"}}}}]}}}}}}},"/store/products/{slug}":{"get":{"tags":["Storefront"],"summary":"Product page (+ related, \"same print\" mate)","operationId":"getStoreProductsSlug","security":[],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"allOf":[{"$ref":"#/components/schemas/Product"},{"type":"object","properties":{"related":{"type":"array","items":{"$ref":"#/components/schemas/Product"}},"mate":{"$ref":"#/components/schemas/Product","nullable":true}}}]}}}]}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/store/cart/quote":{"post":{"tags":["Storefront"],"summary":"Price a bag","operationId":"postStoreCartQuote","security":[{},{"customerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Quote"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"lines":{"type":"array","items":{"$ref":"#/components/schemas/CartLine"}},"gov":{"type":"string","example":"cairo"},"coupon":{"type":"string"},"phone":{"type":"string","description":"For the per-customer coupon limit (guests)"}},"required":["lines"]}}}}}},"/store/orders":{"post":{"tags":["Storefront"],"summary":"Place an order (checkout)","description":"One transaction: validates the address, re-quotes, deducts stock (never oversells), applies the coupon, records history. Transfers start as `pending_verification`.","operationId":"postStoreOrders","security":[{},{"customerAuth":[]}],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"object","properties":{"order":{"$ref":"#/components/schemas/CustomerOrder"},"accessKey":{"type":"string","description":"Keep it: guests open the order with ?key="}}}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Stock changed / item sold out (code STOCK)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutBody"}}}}}},"/store/orders/{number}":{"get":{"tags":["Storefront"],"summary":"Order page (owner or access key)","operationId":"getStoreOrdersNumber","security":[{},{"customerAuth":[]}],"parameters":[{"name":"number","in":"path","required":true,"schema":{"type":"string","example":"ML261021-4068"}},{"name":"key","in":"query","schema":{"type":"string"},"description":"Order access key (guests)"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CustomerOrder"}}}]}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/store/orders/{number}/cancel":{"post":{"tags":["Storefront"],"summary":"Cancel while pending / confirmed","operationId":"postStoreOrdersNumberCancel","security":[{},{"customerAuth":[]}],"parameters":[{"name":"number","in":"path","required":true,"schema":{"type":"string","example":"ML261021-4068"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CustomerOrder"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string"}}}}}}}},"/store/auth/register":{"post":{"tags":["Customer accounts"],"summary":"Create a customer account","operationId":"postStoreAuthRegister","security":[],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"allOf":[{"$ref":"#/components/schemas/Tokens"},{"type":"object","properties":{"customer":{"$ref":"#/components/schemas/Customer"}}}]}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":3},"email":{"type":"string"},"phone":{"type":"string","pattern":"^01[0125][0-9]{8}$"},"pw":{"type":"string","format":"password","description":"8+ characters incl. a number"}},"required":["name","email","phone","pw"]}}}}}},"/store/auth/login":{"post":{"tags":["Customer accounts"],"summary":"Customer sign-in","operationId":"postStoreAuthLogin","security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"allOf":[{"$ref":"#/components/schemas/Tokens"},{"type":"object","properties":{"customer":{"$ref":"#/components/schemas/Customer"}}}]}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string"},"pw":{"type":"string","format":"password"}},"required":["email","pw"]}}}}}},"/store/auth/refresh":{"post":{"tags":["Customer accounts"],"summary":"Rotate the customer refresh token","operationId":"postStoreAuthRefresh","security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Tokens"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"refreshToken":{"type":"string"}},"required":["refreshToken"]}}}}}},"/store/auth/logout":{"post":{"tags":["Customer accounts"],"summary":"Customer sign-out","operationId":"postStoreAuthLogout","security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"refreshToken":{"type":"string"}}}}}}}},"/store/me":{"get":{"tags":["Customer accounts"],"summary":"My account","operationId":"getStoreMe","security":[{"customerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Customer"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Customer accounts"],"summary":"Update name / phone / newsletter","operationId":"patchStoreMe","security":[{"customerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Customer"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"phone":{"type":"string"},"newsletter":{"type":"boolean"}}}}}}}},"/store/me/password":{"post":{"tags":["Customer accounts"],"summary":"Change my password","operationId":"postStoreMePassword","security":[{"customerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"current":{"type":"string","format":"password"},"next":{"type":"string","format":"password"}},"required":["current","next"]}}}}}},"/store/me/orders":{"get":{"tags":["Customer accounts"],"summary":"My orders","operationId":"getStoreMeOrders","security":[{"customerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CustomerOrder"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/store/me/orders/claim":{"post":{"tags":["Customer accounts"],"summary":"Attach guest orders after signing in","operationId":"postStoreMeOrdersClaim","security":[{"customerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"object","properties":{"claimed":{"type":"integer"}}}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"orders":{"type":"array","items":{"type":"object","properties":{"number":{"type":"string"},"key":{"type":"string"}}}}},"required":["orders"]}}}}}},"/store/me/addresses":{"get":{"tags":["Customer accounts"],"summary":"My saved addresses","operationId":"getStoreMeAddresses","security":[{"customerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CustomerAddress"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Customer accounts"],"summary":"Add an address (max 10)","operationId":"postStoreMeAddresses","security":[{"customerAuth":[]}],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CustomerAddress"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerAddress"}}}}}},"/store/me/addresses/{id}":{"patch":{"tags":["Customer accounts"],"summary":"Edit an address","operationId":"patchStoreMeAddressesId","security":[{"customerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerAddress"}}}}},"delete":{"tags":["Customer accounts"],"summary":"Delete an address","operationId":"deleteStoreMeAddressesId","security":[{"customerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/store/me/wishlist":{"get":{"tags":["Customer accounts"],"summary":"My wishlist (product ids)","operationId":"getStoreMeWishlist","security":[{"customerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"integer"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/store/me/wishlist/{productId}":{"put":{"tags":["Customer accounts"],"summary":"Add to wishlist","operationId":"putStoreMeWishlistProductId","security":[{"customerAuth":[]}],"parameters":[{"name":"productId","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"integer"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Customer accounts"],"summary":"Remove from wishlist","operationId":"deleteStoreMeWishlistProductId","security":[{"customerAuth":[]}],"parameters":[{"name":"productId","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"integer"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/store/me/wishlist/merge":{"post":{"tags":["Customer accounts"],"summary":"Merge a guest wishlist","operationId":"postStoreMeWishlistMerge","security":[{"customerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"integer"}}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"integer"}}},"required":["ids"]}}}}}},"/products":{"get":{"tags":["Products"],"summary":"List products","description":"**Permission:** `products.view`","operationId":"getProducts","security":[{"staffAuth":[]}],"parameters":[{"name":"q","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","enum":["active","draft","archived"]}}],"responses":{"200":{"description":"OK — `meta.lowStock` = low-stock threshold","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Product"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Products"],"summary":"Create a product","description":"**Permission:** `products.create`","operationId":"postProducts","security":[{"staffAuth":[]}],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Product"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductForm"}}}}}},"/products/{id}":{"get":{"tags":["Products"],"summary":"Get a product","description":"**Permission:** `products.view`","operationId":"getProductsId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Product"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"tags":["Products"],"summary":"Save a product (full form)","description":"**Permission:** `products.update`","operationId":"putProductsId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Product"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductForm"}}}}},"delete":{"tags":["Products"],"summary":"Delete a product","description":"Refused if the product was ever ordered — archive it instead.\n\n**Permission:** `products.delete`","operationId":"deleteProductsId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/products/{id}/status":{"patch":{"tags":["Products"],"summary":"Change status only","description":"**Permission:** `products.update`","operationId":"patchProductsIdStatus","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Product"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["active","draft","archived"]}},"required":["status"]}}}}}},"/categories":{"get":{"tags":["Categories & types"],"summary":"List categories (with product counts)","description":"Any signed-in staff member.","operationId":"getCategories","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Category"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Categories & types"],"summary":"Create a category","description":"**Permission:** `categories.manage`","operationId":"postCategories","security":[{"staffAuth":[]}],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Category"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryBody"}}}}}},"/categories/order":{"put":{"tags":["Categories & types"],"summary":"Reorder categories","description":"**Permission:** `categories.manage`","operationId":"putCategoriesOrder","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Category"}}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"integer"}}},"required":["ids"]}}}}}},"/categories/{id}":{"patch":{"tags":["Categories & types"],"summary":"Update a category","description":"Removing a size that products still use is refused. Only the fields you send change.\n\n**Permission:** `categories.manage`","operationId":"patchCategoriesId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Category"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryBody"}}}}},"delete":{"tags":["Categories & types"],"summary":"Delete a category","description":"Refused while products or subcategories depend on it.\n\n**Permission:** `categories.manage`","operationId":"deleteCategoriesId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/categories/{id}/size-guide":{"put":{"tags":["Categories & types"],"summary":"Save the size guide","description":"**Permission:** `categories.manage`","operationId":"putCategoriesIdSizeGuide","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Category"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rows":{"type":"array","items":{"$ref":"#/components/schemas/SizeGuideRow"}}},"required":["rows"]}}}}}},"/styles":{"get":{"tags":["Categories & types"],"summary":"List pajama types","operationId":"getStyles","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK — `meta.icons` = allowed icons","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Style"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Categories & types"],"summary":"Create a type","description":"**Permission:** `categories.manage`","operationId":"postStyles","security":[{"staffAuth":[]}],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Style"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StyleBody"}}}}}},"/styles/order":{"put":{"tags":["Categories & types"],"summary":"Reorder types","description":"**Permission:** `categories.manage`","operationId":"putStylesOrder","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Style"}}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"integer"}}},"required":["ids"]}}}}}},"/styles/{id}":{"patch":{"tags":["Categories & types"],"summary":"Update a type","description":"**Permission:** `categories.manage`","operationId":"patchStylesId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Style"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StyleBody"}}}}},"delete":{"tags":["Categories & types"],"summary":"Delete a type","description":"Refused while products use it; at least one type must remain.\n\n**Permission:** `categories.manage`","operationId":"deleteStylesId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/inventory":{"get":{"tags":["Inventory"],"summary":"Every variant with stock","description":"**Permission:** `inventory.view`","operationId":"getInventory","security":[{"staffAuth":[]}],"parameters":[{"name":"q","in":"query","schema":{"type":"string"}},{"name":"low","in":"query","schema":{"type":"string","enum":["true"]},"description":"Only stock ≤ low-stock threshold"}],"responses":{"200":{"description":"OK — `meta.lowStock` = threshold","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/InventoryRow"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/inventory/movements":{"get":{"tags":["Inventory"],"summary":"Recent stock movements","description":"**Permission:** `inventory.view`","operationId":"getInventoryMovements","security":[{"staffAuth":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"default":30}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StockMovement"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/inventory/adjust":{"post":{"tags":["Inventory"],"summary":"Adjust stock","description":"**Permission:** `inventory.adjust`","operationId":"postInventoryAdjust","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"object","properties":{"sku":{"type":"string"},"stock":{"type":"integer"}}}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sku":{"type":"string"},"delta":{"type":"integer","example":-2,"description":"Not 0; result can’t go below 0"},"reason":{"type":"string","minLength":3,"example":"تالف"}},"required":["sku","delta","reason"]}}}}}},"/banners":{"get":{"tags":["Banners & coupons"],"summary":"List banners","description":"**Permission:** `banners.manage`","operationId":"getBanners","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Banner"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Banners & coupons"],"summary":"Create a banner","description":"**Permission:** `banners.manage`","operationId":"postBanners","security":[{"staffAuth":[]}],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Banner"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BannerBody"}}}}}},"/banners/order":{"put":{"tags":["Banners & coupons"],"summary":"Reorder banners","description":"**Permission:** `banners.manage`","operationId":"putBannersOrder","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Banner"}}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"integer"}}},"required":["ids"]}}}}}},"/banners/{id}":{"patch":{"tags":["Banners & coupons"],"summary":"Update a banner (only sent fields change)","description":"**Permission:** `banners.manage`","operationId":"patchBannersId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Banner"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BannerBody"}}}}},"delete":{"tags":["Banners & coupons"],"summary":"Delete a banner","description":"**Permission:** `banners.manage`","operationId":"deleteBannersId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/coupons":{"get":{"tags":["Banners & coupons"],"summary":"List coupons","description":"**Permission:** `coupons.manage`","operationId":"getCoupons","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Coupon"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Banners & coupons"],"summary":"Create a coupon","description":"**Permission:** `coupons.manage`","operationId":"postCoupons","security":[{"staffAuth":[]}],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Coupon"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Code already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CouponBody"}}}}}},"/coupons/{id}":{"patch":{"tags":["Banners & coupons"],"summary":"Update a coupon (only sent fields change)","description":"**Permission:** `coupons.manage`","operationId":"patchCouponsId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Coupon"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Code already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CouponBody"}}}}}},"/orders":{"get":{"tags":["Orders & customers"],"summary":"List orders","description":"**Permission:** `orders.view`","operationId":"getOrders","security":[{"staffAuth":[]}],"parameters":[{"name":"q","in":"query","schema":{"type":"string"},"description":"Order number, name or phone"},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","confirmed","processing","ready","shipped","out","delivered","cancelled","returned"]}},{"name":"method","in":"query","schema":{"type":"string","enum":["cod","instapay","vfcash"]}},{"name":"pay","in":"query","schema":{"type":"string","enum":["pending","pending_verification","paid","rejected","refunded"]}},{"name":"sort","in":"query","schema":{"type":"string","enum":["number","created","name","total","method","pay","status"]}},{"name":"dir","in":"query","schema":{"type":"string","enum":["asc","desc"]}},{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"default":10}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OrderRow"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/orders/export.csv":{"get":{"tags":["Orders & customers"],"summary":"Export orders as CSV (max 5000)","description":"**Permission:** `orders.view`","operationId":"getOrdersExportCsv","security":[{"staffAuth":[]}],"parameters":[{"name":"q","in":"query","schema":{"type":"string"},"description":"Order number, name or phone"},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","confirmed","processing","ready","shipped","out","delivered","cancelled","returned"]}},{"name":"method","in":"query","schema":{"type":"string","enum":["cod","instapay","vfcash"]}},{"name":"pay","in":"query","schema":{"type":"string","enum":["pending","pending_verification","paid","rejected","refunded"]}}],"responses":{"200":{"description":"CSV file (UTF-8 with BOM)","content":{"text/csv":{"schema":{"type":"string"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/orders/{number}":{"get":{"tags":["Orders & customers"],"summary":"Order detail","description":"**Permission:** `orders.view`","operationId":"getOrdersNumber","security":[{"staffAuth":[]}],"parameters":[{"name":"number","in":"path","required":true,"schema":{"type":"string","example":"ML261021-4068"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrderDetail"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/orders/{number}/status":{"post":{"tags":["Orders & customers"],"summary":"Move an order to the next status","description":"Only allowed transitions; transfer orders need an approved payment before `confirmed`; cancel/return restock.\n\n**Permission:** `orders.update_status`","operationId":"postOrdersNumberStatus","security":[{"staffAuth":[]}],"parameters":[{"name":"number","in":"path","required":true,"schema":{"type":"string","example":"ML261021-4068"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrderDetail"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"to":{"type":"string","enum":["pending","confirmed","processing","ready","shipped","out","delivered","cancelled","returned"]},"note":{"type":"string"}},"required":["to"]}}}}}},"/orders/{number}/payment":{"post":{"tags":["Orders & customers"],"summary":"Approve / reject a transfer, or mark COD collected","description":"COD can be marked collected only after `delivered`.\n\n**Permission:** `payments.verify`","operationId":"postOrdersNumberPayment","security":[{"staffAuth":[]}],"parameters":[{"name":"number","in":"path","required":true,"schema":{"type":"string","example":"ML261021-4068"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrderDetail"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"approve":{"type":"boolean"},"reason":{"type":"string"}},"required":["approve"]}}}}}},"/orders/{number}/notes":{"post":{"tags":["Orders & customers"],"summary":"Add an internal note","description":"**Permission:** `orders.view`","operationId":"postOrdersNumberNotes","security":[{"staffAuth":[]}],"parameters":[{"name":"number","in":"path","required":true,"schema":{"type":"string","example":"ML261021-4068"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrderDetail"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string","maxLength":1000}},"required":["text"]}}}}}},"/customers":{"get":{"tags":["Orders & customers"],"summary":"Customers (accounts + guests by phone)","description":"**Permission:** `customers.view`","operationId":"getCustomers","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CustomerSummary"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/overview":{"get":{"tags":["Reports"],"summary":"Store overview","description":"Revenue = paid orders that are not cancelled/returned, excluding delivery fees.\n\n**Permission:** `dashboard.view`","operationId":"getReportsOverview","security":[{"staffAuth":[]}],"parameters":[{"name":"range","in":"query","schema":{"type":"integer","enum":[7,30,90,0]},"description":"Days; 0 = all time"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Overview"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/reports/badges":{"get":{"tags":["Reports"],"summary":"Sidebar badge counts","operationId":"getReportsBadges","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"object","properties":{"orders":{"type":"integer"},"payments":{"type":"integer"},"tasks":{"type":"integer"}}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tasks":{"get":{"tags":["Tasks"],"summary":"List tasks","description":"**Permission:** `tasks.view_assigned`","operationId":"getTasks","security":[{"staffAuth":[]}],"parameters":[{"name":"scope","in":"query","schema":{"type":"string","enum":["mine","all"]}}],"responses":{"200":{"description":"OK — `meta.canManage`","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Task"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Tasks"],"summary":"Create a task","description":"**Permission:** `tasks.create`","operationId":"postTasks","security":[{"staffAuth":[]}],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Task"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"priority":{"type":"string","enum":["low","medium","high","urgent"],"default":"medium"},"dueAt":{"type":"string","format":"date-time"},"assigneeIds":{"type":"array","items":{"type":"integer"}}},"required":["title","dueAt","assigneeIds"]}}}}}},"/tasks/people":{"get":{"tags":["Tasks"],"summary":"Staff I can assign","description":"**Permission:** `tasks.create`","operationId":"getTasksPeople","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"}}}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tasks/{id}":{"get":{"tags":["Tasks"],"summary":"Task with comments","description":"**Permission:** `tasks.view_assigned`","operationId":"getTasksId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Task"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tasks/{id}/status":{"post":{"tags":["Tasks"],"summary":"Change task status","description":"Only a manager or the creator can mark it done.\n\n**Permission:** `tasks.update_status`","operationId":"postTasksIdStatus","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Task"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["todo","doing","review","done","cancelled"]}},"required":["status"]}}}}}},"/tasks/{id}/comments":{"post":{"tags":["Tasks"],"summary":"Add a progress update","description":"**Permission:** `tasks.view_assigned`","operationId":"postTasksIdComments","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Task"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string"}},"required":["text"]}}}}}},"/notifications":{"get":{"tags":["Notifications"],"summary":"My notifications","operationId":"getNotifications","security":[{"staffAuth":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"default":40}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Notification"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/notifications/unread-count":{"get":{"tags":["Notifications"],"summary":"Unread count","operationId":"getNotificationsUnreadCount","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"object","properties":{"count":{"type":"integer"}}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/notifications/read-all":{"post":{"tags":["Notifications"],"summary":"Mark all as read","operationId":"postNotificationsReadAll","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"object","properties":{"marked":{"type":"integer"}}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/notifications/{id}/read":{"post":{"tags":["Notifications"],"summary":"Mark one as read","operationId":"postNotificationsIdRead","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/settings":{"get":{"tags":["Settings"],"summary":"Get store settings","description":"**Permission:** `settings.manage`","operationId":"getSettings","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"allOf":[{"$ref":"#/components/schemas/Settings"},{"type":"object","properties":{"governorates":{"type":"array","items":{"$ref":"#/components/schemas/Governorate"}}}}]}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"tags":["Settings"],"summary":"Replace store settings","description":"At least one payment method and one governorate must stay on; InstaPay / Vodafone Cash details are validated when switched on.\n\n**Permission:** `settings.manage`","operationId":"putSettings","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Settings"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Settings"}}}}}},"/audit-logs":{"get":{"tags":["Activity log"],"summary":"Search the activity log","description":"**Permission:** `audit.view`","operationId":"getAuditLogs","security":[{"staffAuth":[]}],"parameters":[{"name":"resource","in":"query","schema":{"type":"string"}},{"name":"action","in":"query","schema":{"type":"string"}},{"name":"actorId","in":"query","schema":{"type":"integer"}},{"name":"q","in":"query","schema":{"type":"string"}},{"name":"from","in":"query","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","schema":{"type":"string","format":"date"}},{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"default":60}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AuditLog"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/audit-logs/filters":{"get":{"tags":["Activity log"],"summary":"Resources and actions seen so far","description":"**Permission:** `audit.view`","operationId":"getAuditLogsFilters","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"object","properties":{"resources":{"type":"array","items":{"type":"string"}},"actions":{"type":"array","items":{"type":"string"}},"resourceActions":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/employees":{"get":{"tags":["Factory · Employees"],"summary":"Active employees","description":"**Permission:** `employees.view`","operationId":"getEmployees","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Employee"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Factory · Employees"],"summary":"Add an employee","description":"**Permission:** `employees.manage`","operationId":"postEmployees","security":[{"staffAuth":[]}],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Employee"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmployeeBody"}}}}}},"/employees/{id}":{"get":{"tags":["Factory · Employees"],"summary":"One employee","description":"**Permission:** `employees.view`","operationId":"getEmployeesId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Employee"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"tags":["Factory · Employees"],"summary":"Edit an employee","description":"**Permission:** `employees.manage`","operationId":"putEmployeesId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Employee"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmployeeBody"}}}}},"delete":{"tags":["Factory · Employees"],"summary":"Remove an employee (soft delete)","description":"**Permission:** `employees.manage`","operationId":"deleteEmployeesId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/attendance":{"get":{"tags":["Factory · Attendance"],"summary":"Attendance for a month","description":"**Permission:** `attendance.view`","operationId":"getAttendance","security":[{"staffAuth":[]}],"parameters":[{"name":"month","in":"query","schema":{"type":"string","example":"2026-10"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Attendance"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Factory · Attendance"],"summary":"Record one day for one employee","description":"**Permission:** `attendance.manage`","operationId":"postAttendance","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Attendance"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"employee_id":{"type":"integer"},"date":{"type":"string","format":"date"},"status":{"type":"string","enum":["present","absent","leave"]},"day_fraction":{"type":"number"},"notes":{"type":"string"}},"required":["employee_id","date","status"]}}}}}},"/attendance/day/{date}":{"get":{"tags":["Factory · Attendance"],"summary":"Attendance for one day","description":"**Permission:** `attendance.view`","operationId":"getAttendanceDayDate","security":[{"staffAuth":[]}],"parameters":[{"name":"date","in":"path","required":true,"schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Attendance"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/attendance/summary/{month}":{"get":{"tags":["Factory · Attendance"],"summary":"Monthly summary per employee (fractional)","description":"**Permission:** `attendance.view`","operationId":"getAttendanceSummaryMonth","security":[{"staffAuth":[]}],"parameters":[{"name":"month","in":"path","required":true,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}$","example":"2026-10"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"employee_id":{"type":"integer"},"absent_days":{"type":"number"},"leave_days":{"type":"number"},"present_days":{"type":"number"},"friday_present_days":{"type":"number"},"partial_day_records":{"type":"integer"},"total_recorded":{"type":"integer"}}}}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/attendance/bulk":{"post":{"tags":["Factory · Attendance"],"summary":"Save a whole day's attendance","description":"**Permission:** `attendance.manage`","operationId":"postAttendanceBulk","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"object","properties":{"message":{"type":"string"},"saved":{"type":"integer"},"deleted":{"type":"integer"}}}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"date":{"type":"string","format":"date"},"records":{"type":"array","items":{"type":"object","properties":{"employee_id":{"type":"integer"},"status":{"type":"string","enum":["present","absent","leave"]},"day_fraction":{"type":"number"},"notes":{"type":"string"}}}},"deletions":{"type":"array","items":{"type":"integer","description":"employee ids to clear for that date"}}},"required":["date","records"]}}}}}},"/attendance/{id}":{"delete":{"tags":["Factory · Attendance"],"summary":"Delete an attendance row","description":"**Permission:** `attendance.manage`","operationId":"deleteAttendanceId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/salary/months":{"get":{"tags":["Factory · Salaries"],"summary":"Months that have salary records","description":"**Permission:** `salary.view`","operationId":"getSalaryMonths","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"string","example":"2026-10"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/salary/fridays/{month}":{"get":{"tags":["Factory · Salaries"],"summary":"Number of Fridays in a month","description":"**Permission:** `salary.view`","operationId":"getSalaryFridaysMonth","security":[{"staffAuth":[]}],"parameters":[{"name":"month","in":"path","required":true,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}$","example":"2026-10"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"object","properties":{"month":{"type":"string","example":"2026-10"},"total_fridays":{"type":"integer","example":5}}}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/salary/employee/{id}":{"get":{"tags":["Factory · Salaries"],"summary":"An employee's salary history","description":"**Permission:** `salary.view`","operationId":"getSalaryEmployeeId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SalaryRecord"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/salary":{"get":{"tags":["Factory · Salaries"],"summary":"Salary records","description":"**Permission:** `salary.view`","operationId":"getSalary","security":[{"staffAuth":[]}],"parameters":[{"name":"month","in":"query","schema":{"type":"string","example":"2026-10"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SalaryRecord"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Factory · Salaries"],"summary":"Create a salary record","description":"**Permission:** `salary.manage`","operationId":"postSalary","security":[{"staffAuth":[]}],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SalaryRecord"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Record already exists for that month","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SalaryBody"}}}}}},"/salary/{id}":{"put":{"tags":["Factory · Salaries"],"summary":"Recalculate a salary record","description":"**Permission:** `salary.manage`","operationId":"putSalaryId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SalaryRecord"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SalaryBody"}}}}},"delete":{"tags":["Factory · Salaries"],"summary":"Delete a salary record","description":"**Permission:** `salary.manage`","operationId":"deleteSalaryId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/cash-advances/totals/{month}":{"get":{"tags":["Factory · Cash advances"],"summary":"Advance totals per employee for a month","description":"**Permission:** `salary.view`","operationId":"getCashAdvancesTotalsMonth","security":[{"staffAuth":[]}],"parameters":[{"name":"month","in":"path","required":true,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}$","example":"2026-10"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"employee_id":{"type":"integer"},"total_advance":{"type":"number"}}}}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/cash-advances/employee/{id}":{"get":{"tags":["Factory · Cash advances"],"summary":"An employee's advances","description":"**Permission:** `salary.view`","operationId":"getCashAdvancesEmployeeId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CashAdvance"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/cash-advances":{"get":{"tags":["Factory · Cash advances"],"summary":"List advances","description":"**Permission:** `salary.view`","operationId":"getCashAdvances","security":[{"staffAuth":[]}],"parameters":[{"name":"month","in":"query","schema":{"type":"string"}},{"name":"employee_id","in":"query","schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CashAdvance"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Factory · Cash advances"],"summary":"Record an advance","description":"**Permission:** `salary.manage`","operationId":"postCashAdvances","security":[{"staffAuth":[]}],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CashAdvance"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CashAdvanceBody"}}}}}},"/cash-advances/{id}":{"put":{"tags":["Factory · Cash advances"],"summary":"Edit an advance","description":"**Permission:** `salary.manage`","operationId":"putCashAdvancesId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CashAdvance"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CashAdvanceBody"}}}}},"delete":{"tags":["Factory · Cash advances"],"summary":"Delete an advance","description":"**Permission:** `salary.manage`","operationId":"deleteCashAdvancesId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/leaves/totals/{month}":{"get":{"tags":["Factory · Leaves (استئذان)"],"summary":"Leave totals per employee for a month","description":"**Permission:** `salary.view`","operationId":"getLeavesTotalsMonth","security":[{"staffAuth":[]}],"parameters":[{"name":"month","in":"path","required":true,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}$","example":"2026-10"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"employee_id":{"type":"integer"},"errand_count":{"type":"number"},"early_leave_hours":{"type":"number"},"total_deduction":{"type":"number"}}}}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/leaves/employee/{id}":{"get":{"tags":["Factory · Leaves (استئذان)"],"summary":"An employee's leaves","description":"**Permission:** `salary.view`","operationId":"getLeavesEmployeeId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Leave"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/leaves":{"get":{"tags":["Factory · Leaves (استئذان)"],"summary":"List leaves","description":"**Permission:** `salary.view`","operationId":"getLeaves","security":[{"staffAuth":[]}],"parameters":[{"name":"month","in":"query","schema":{"type":"string"}},{"name":"employee_id","in":"query","schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Leave"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Factory · Leaves (استئذان)"],"summary":"Record a leave","description":"**Permission:** `salary.manage`","operationId":"postLeaves","security":[{"staffAuth":[]}],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Leave"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeaveBody"}}}}}},"/leaves/{id}":{"put":{"tags":["Factory · Leaves (استئذان)"],"summary":"Edit a leave","description":"**Permission:** `salary.manage`","operationId":"putLeavesId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Leave"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeaveBody"}}}}},"delete":{"tags":["Factory · Leaves (استئذان)"],"summary":"Delete a leave","description":"**Permission:** `salary.manage`","operationId":"deleteLeavesId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/ledger/summary":{"get":{"tags":["Factory · Ledger"],"summary":"Totals owed to / by the factory","description":"**Permission:** `ledger.view`","operationId":"getLedgerSummary","security":[{"staffAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"object","properties":{"totalDebtors":{"type":"number"},"totalCreditors":{"type":"number"},"net":{"type":"number"},"debtorCount":{"type":"integer"},"creditorCount":{"type":"integer"}}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/ledger/parties":{"get":{"tags":["Factory · Ledger"],"summary":"List parties with balances","description":"**Permission:** `ledger.view`","operationId":"getLedgerParties","security":[{"staffAuth":[]}],"parameters":[{"name":"type","in":"query","schema":{"type":"string","enum":["debtor","creditor"]}},{"name":"search","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/LedgerParty"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Factory · Ledger"],"summary":"Add a party","description":"**Permission:** `ledger.manage`","operationId":"postLedgerParties","security":[{"staffAuth":[]}],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/LedgerParty"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string","enum":["debtor","creditor"],"default":"debtor"},"phone":{"type":"string"},"notes":{"type":"string"}},"required":["name"]}}}}}},"/ledger/parties/{id}":{"get":{"tags":["Factory · Ledger"],"summary":"One party with balance","description":"**Permission:** `ledger.view`","operationId":"getLedgerPartiesId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/LedgerParty"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"tags":["Factory · Ledger"],"summary":"Edit a party","description":"**Permission:** `ledger.manage`","operationId":"putLedgerPartiesId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/LedgerParty"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string","enum":["debtor","creditor"]},"phone":{"type":"string"},"notes":{"type":"string"},"is_active":{"type":"integer"}}}}}}},"delete":{"tags":["Factory · Ledger"],"summary":"Remove a party (balance must be 0)","description":"**Permission:** `ledger.manage`","operationId":"deleteLedgerPartiesId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/ledger/transactions":{"get":{"tags":["Factory · Ledger"],"summary":"List transactions","description":"**Permission:** `ledger.view`","operationId":"getLedgerTransactions","security":[{"staffAuth":[]}],"parameters":[{"name":"party_id","in":"query","schema":{"type":"integer"}},{"name":"type","in":"query","schema":{"type":"string","enum":["debit","payment"]}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/LedgerTransaction"}}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Factory · Ledger"],"summary":"Record a debit or payment","description":"**Permission:** `ledger.manage`","operationId":"postLedgerTransactions","security":[{"staffAuth":[]}],"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"object","properties":{"transaction":{"$ref":"#/components/schemas/LedgerTransaction"},"new_balance":{"type":"number"}}}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"party_id":{"type":"integer"},"type":{"type":"string","enum":["debit","payment"]},"amount":{"type":"number","exclusiveMinimum":0},"date":{"type":"string","format":"date"},"description":{"type":"string"}},"required":["party_id","type","amount","date"]}}}}}},"/ledger/transactions/{id}":{"put":{"tags":["Factory · Ledger"],"summary":"Edit a transaction","description":"**Permission:** `ledger.manage`","operationId":"putLedgerTransactionsId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/LedgerTransaction"}}}]}}}},"400":{"description":"Validation / business rule failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amount":{"type":"number"},"date":{"type":"string","format":"date"},"description":{"type":"string"}}}}}}},"delete":{"tags":["Factory · Ledger"],"summary":"Delete a transaction","description":"**Permission:** `ledger.manage`","operationId":"deleteLedgerTransactionsId","security":[{"staffAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"description":"Only a message"}}}]}}}},"401":{"description":"Missing, invalid or expired access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing permission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/health":{"servers":[{"url":"/api"}],"get":{"tags":["System"],"summary":"Health check","operationId":"getHealth","security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Envelope"},{"type":"object","properties":{"data":{"type":"object","properties":{"status":{"type":"string","example":"ok"},"environment":{"type":"string","example":"production"}}}}}]}}}}}}}},"components":{"securitySchemes":{"staffAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Staff access token from POST /auth/login"},"customerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Customer access token from POST /store/auth/login"}},"schemas":{"Envelope":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"تمت العملية بنجاح"},"data":{"description":"Payload (see each operation)"},"meta":{"$ref":"#/components/schemas/PageMeta"},"path":{"type":"string","example":"/api/v1/orders"},"timestamp":{"type":"string","format":"date-time"},"requestId":{"type":"string","example":"req-mvilfrjw-fcf476"}}},"Error":{"type":"object","properties":{"success":{"type":"boolean","example":false},"message":{"type":"string","description":"Arabic message","example":"من فضلك راجعي الحقول المحددة."},"messageEn":{"type":"string","example":"Please fix the highlighted fields."},"errors":{"type":"object","additionalProperties":true,"description":"Field → message (validation errors)","example":{"phone":"Enter a valid Egyptian mobile (01xxxxxxxxx)"}},"code":{"type":"string","description":"Machine code on some errors: STOCK, FIELDS, TOKEN_EXPIRED…"},"path":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"requestId":{"type":"string"}}},"PageMeta":{"type":"object","properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"},"hasNextPage":{"type":"boolean"},"hasPrevPage":{"type":"boolean"}}},"Localized":{"type":"object","properties":{"en":{"type":"string","example":"Navy"},"ar":{"type":"string","example":"كحلي"}}},"Tokens":{"type":"object","properties":{"accessToken":{"type":"string","description":"JWT, 15 min"},"refreshToken":{"type":"string","description":"Opaque, rotates on every refresh, 30 days"},"expiresIn":{"type":"string","example":"15m"}}},"StaffProfile":{"type":"object","properties":{"id":{"type":"integer"},"username":{"type":"string"},"fullName":{"type":"string"},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"avatarUrl":{"type":"string","nullable":true},"isSuper":{"type":"boolean"},"isRoot":{"type":"boolean"},"roles":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"key":{"type":"string"},"nameEn":{"type":"string"},"nameAr":{"type":"string"}}}},"permissions":{"type":"array","items":{"type":"string","example":"orders.view"}}}},"StaffUser":{"type":"object","properties":{"id":{"type":"integer"},"username":{"type":"string"},"fullName":{"type":"string"},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"avatarUrl":{"type":"string","nullable":true},"responsibility":{"type":"string","nullable":true},"isActive":{"type":"boolean"},"isRoot":{"type":"boolean"},"permissions":{"type":"array","items":{"type":"string"}},"roles":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"key":{"type":"string"},"nameEn":{"type":"string"},"nameAr":{"type":"string"},"isLocked":{"type":"boolean"}}}},"openTasks":{"type":"integer"},"lastLoginAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string"}}},"Session":{"type":"object","properties":{"id":{"type":"string"},"userAgent":{"type":"string"},"ip":{"type":"string"},"lastActiveAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"isCurrent":{"type":"boolean"}}},"PermissionGroup":{"type":"object","properties":{"key":{"type":"string","example":"orders"},"en":{"type":"string"},"ar":{"type":"string"},"items":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","example":"orders.view"},"en":{"type":"string"},"ar":{"type":"string"}}}}}},"Role":{"type":"object","properties":{"id":{"type":"integer"},"key":{"type":"string","example":"order_manager"},"nameEn":{"type":"string"},"nameAr":{"type":"string"},"descriptionEn":{"type":"string","nullable":true},"descriptionAr":{"type":"string","nullable":true},"isSystem":{"type":"boolean"},"isLocked":{"type":"boolean","description":"Super Admin — every permission, not editable"},"isActive":{"type":"boolean"},"permissions":{"type":"array","items":{"type":"string"}},"userCount":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"Upload":{"type":"object","properties":{"id":{"type":"integer"},"key":{"type":"string","example":"products/2026/10/AJiCGA5L3ZuYkY0K.webp"},"url":{"type":"string","example":"/uploads/products/2026/10/AJiCGA5L3ZuYkY0K.webp"},"purpose":{"type":"string"},"originalName":{"type":"string"},"mimeType":{"type":"string","example":"image/webp"},"size":{"type":"integer"},"width":{"type":"integer","nullable":true},"height":{"type":"integer","nullable":true},"uploadedById":{"type":"integer","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"UploadPurpose":{"type":"object","properties":{"purpose":{"type":"string","enum":["PRODUCT_IMAGE","CATEGORY_IMAGE","BANNER_IMAGE","AVATAR","PAYMENT_PROOF"]},"maxBytes":{"type":"integer"},"maxEdge":{"type":"integer"},"accepted":{"type":"array","items":{"type":"string"}},"output":{"type":"string","example":"image/webp"}}},"SizeGuideRow":{"type":"object","properties":{"size":{"type":"string","example":"M"},"age":{"type":"string","description":"Kids only"},"height":{"type":"string","example":"163–155"},"weight":{"type":"string","example":"65–55"}},"required":["size"]},"Category":{"type":"object","properties":{"id":{"type":"integer"},"slug":{"type":"string","example":"women"},"name":{"$ref":"#/components/schemas/Localized"},"desc":{"$ref":"#/components/schemas/Localized"},"parentId":{"type":"integer","nullable":true},"imageUrl":{"type":"string","nullable":true},"sizes":{"type":"array","items":{"type":"string","example":"M"}},"sizeGuide":{"type":"array","items":{"$ref":"#/components/schemas/SizeGuideRow"}},"isActive":{"type":"boolean"},"sortOrder":{"type":"integer"},"productCount":{"type":"integer","description":"GET /categories only"},"activeCount":{"type":"integer"}}},"CategoryBody":{"type":"object","properties":{"name":{"$ref":"#/components/schemas/Localized"},"desc":{"$ref":"#/components/schemas/Localized"},"parentId":{"type":"integer","nullable":true},"imageUrl":{"type":"string","nullable":true},"sizes":{"type":"array","items":{"type":"string"}},"sizeGuide":{"type":"array","items":{"$ref":"#/components/schemas/SizeGuideRow"}},"isActive":{"type":"boolean"}},"required":["name"]},"Style":{"type":"object","properties":{"id":{"type":"integer"},"slug":{"type":"string"},"name":{"$ref":"#/components/schemas/Localized"},"desc":{"$ref":"#/components/schemas/Localized"},"icon":{"type":"string","example":"checkroom"},"isActive":{"type":"boolean"},"sortOrder":{"type":"integer"},"productCount":{"type":"integer"}}},"StyleBody":{"type":"object","properties":{"name":{"$ref":"#/components/schemas/Localized"},"desc":{"$ref":"#/components/schemas/Localized"},"icon":{"type":"string","description":"One of the icons listed in GET /styles meta.icons"},"isActive":{"type":"boolean"}},"required":["name"]},"ProductColor":{"type":"object","properties":{"id":{"type":"integer"},"key":{"type":"string","example":"navy"},"name":{"$ref":"#/components/schemas/Localized"},"hex":{"type":"string","example":"#1f2a55"},"images":{"type":"array","items":{"type":"string","description":"Upload URL; first = primary"}}}},"ProductVariant":{"type":"object","properties":{"id":{"type":"integer"},"sku":{"type":"string","example":"ML-NSA-NAV-M"},"colorId":{"type":"integer"},"colorKey":{"type":"string"},"size":{"type":"string"},"stock":{"type":"integer"},"price":{"type":"integer","description":"Override in EGP","nullable":true}}},"Product":{"type":"object","properties":{"id":{"type":"integer"},"slug":{"type":"string"},"code":{"type":"string","example":"NSA","description":"Generated by the server"},"name":{"$ref":"#/components/schemas/Localized"},"desc":{"$ref":"#/components/schemas/Localized"},"fabric":{"$ref":"#/components/schemas/Localized"},"category":{"type":"object","properties":{"id":{"type":"integer"},"slug":{"type":"string"},"name":{"$ref":"#/components/schemas/Localized"},"sizes":{"type":"array","items":{"type":"string"}},"sizeGuide":{"type":"array","items":{"$ref":"#/components/schemas/SizeGuideRow"}},"isActive":{"type":"boolean"}},"nullable":true},"style":{"type":"object","properties":{"id":{"type":"integer"},"slug":{"type":"string"},"name":{"$ref":"#/components/schemas/Localized"},"icon":{"type":"string"},"isActive":{"type":"boolean"}},"nullable":true},"price":{"type":"integer","description":"EGP"},"salePrice":{"type":"integer","nullable":true},"unitPrice":{"type":"integer","description":"salePrice ?? price"},"status":{"type":"string","enum":["active","draft","archived"]},"isNew":{"type":"boolean"},"isBest":{"type":"boolean"},"featured":{"type":"boolean"},"popularity":{"type":"integer"},"colors":{"type":"array","items":{"$ref":"#/components/schemas/ProductColor"}},"scenes":{"type":"array","items":{"type":"string","description":"Lifestyle photo URLs"}},"variants":{"type":"array","items":{"$ref":"#/components/schemas/ProductVariant"}},"stock":{"type":"integer","description":"Sum of variant stock"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ProductForm":{"type":"object","properties":{"name":{"$ref":"#/components/schemas/Localized"},"desc":{"$ref":"#/components/schemas/Localized"},"fabric":{"$ref":"#/components/schemas/Localized"},"slug":{"type":"string","description":"Optional; derived from the English name"},"categoryId":{"type":"integer"},"styleId":{"type":"integer"},"price":{"type":"integer","minimum":1},"salePrice":{"type":"integer","description":"Must be lower than price","nullable":true},"status":{"type":"string","enum":["active","draft","archived"],"default":"draft"},"isNew":{"type":"boolean"},"isBest":{"type":"boolean"},"featured":{"type":"boolean"},"colors":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","description":"Existing colour id (edit)"},"key":{"type":"string","example":"navy"},"name":{"$ref":"#/components/schemas/Localized"},"hex":{"type":"string"},"images":{"type":"array","items":{"type":"string"}}},"required":["key","name","hex"]}},"scenes":{"type":"array","items":{"type":"string"}},"variants":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"sku":{"type":"string","description":"Leave empty → ML-<code>-<colour>-<size>"},"colorKey":{"type":"string"},"size":{"type":"string"},"stock":{"type":"integer","minimum":0},"price":{"type":"integer","nullable":true}},"required":["colorKey","size","stock"]}}},"required":["name","categoryId","styleId","price","colors","variants"],"description":"Full product form. The product `code` is generated on create and never changes (any `code` sent is ignored). Sizes must belong to the category; colour keys, SKUs and colour+size pairs must be unique."},"InventoryRow":{"type":"object","properties":{"id":{"type":"integer"},"sku":{"type":"string"},"productId":{"type":"integer"},"productStatus":{"type":"string"},"name":{"$ref":"#/components/schemas/Localized"},"color":{"$ref":"#/components/schemas/Localized"},"hex":{"type":"string"},"size":{"type":"string"},"stock":{"type":"integer"},"low":{"type":"boolean"}}},"StockMovement":{"type":"object","properties":{"id":{"type":"integer"},"sku":{"type":"string"},"delta":{"type":"integer","example":-2},"reason":{"type":"string","example":"تالف"},"actorType":{"type":"string","enum":["user","customer","system"]},"by":{"type":"string","nullable":true},"at":{"type":"string","format":"date-time"}}},"Banner":{"type":"object","properties":{"id":{"type":"integer"},"placement":{"type":"string","enum":["hero","bar"]},"tone":{"type":"string","enum":["cream","red","ink"]},"title":{"$ref":"#/components/schemas/Localized"},"eyebrow":{"$ref":"#/components/schemas/Localized"},"sub":{"$ref":"#/components/schemas/Localized"},"cta":{"$ref":"#/components/schemas/Localized"},"link":{"type":"string","example":"cat:women","description":"cat:<slug> | cat:all | cat:new | cat:sale | product:<slug>","nullable":true},"image":{"type":"string","nullable":true},"image2":{"type":"string","nullable":true},"startsAt":{"type":"string","format":"date-time"},"endsAt":{"type":"string","format":"date-time"},"isActive":{"type":"boolean"},"order":{"type":"integer"}}},"BannerBody":{"type":"object","properties":{"placement":{"type":"string","enum":["hero","bar"]},"tone":{"type":"string","enum":["cream","red","ink"],"default":"cream"},"title":{"$ref":"#/components/schemas/Localized"},"eyebrow":{"$ref":"#/components/schemas/Localized"},"sub":{"$ref":"#/components/schemas/Localized"},"cta":{"$ref":"#/components/schemas/Localized"},"link":{"type":"string","nullable":true},"image":{"type":"string","description":"Required for hero","nullable":true},"image2":{"type":"string","nullable":true},"startsAt":{"type":"string","format":"date-time"},"endsAt":{"type":"string","format":"date-time"},"isActive":{"type":"boolean","default":true}},"required":["placement","title","startsAt","endsAt"]},"Coupon":{"type":"object","properties":{"id":{"type":"integer"},"code":{"type":"string","example":"WELCOME10"},"type":{"type":"string","enum":["pct","fixed"]},"value":{"type":"integer"},"minOrder":{"type":"integer"},"startsAt":{"type":"string","format":"date-time"},"endsAt":{"type":"string","format":"date-time"},"usageLimit":{"type":"integer"},"usedCount":{"type":"integer"},"perCustomer":{"type":"integer"},"scope":{"type":"array","items":{"type":"string","description":"Category slug"},"nullable":true},"isActive":{"type":"boolean"}}},"CouponBody":{"type":"object","properties":{"code":{"type":"string","pattern":"^[A-Z0-9]{4,16}$"},"type":{"type":"string","enum":["pct","fixed"]},"value":{"type":"integer","description":"pct ≤ 90"},"minOrder":{"type":"integer","default":0},"startsAt":{"type":"string","format":"date-time"},"endsAt":{"type":"string","format":"date-time"},"usageLimit":{"type":"integer","default":100},"perCustomer":{"type":"integer","default":1},"scope":{"type":"array","items":{"type":"string"},"nullable":true},"isActive":{"type":"boolean","default":true}},"required":["code","type","value","startsAt","endsAt"]},"Address":{"type":"object","properties":{"gov":{"type":"string","example":"cairo"},"area":{"type":"string"},"street":{"type":"string"},"building":{"type":"string"},"floor":{"type":"string","nullable":true},"apt":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true}}},"OrderItem":{"type":"object","properties":{"sku":{"type":"string"},"productId":{"type":"integer","nullable":true},"name":{"$ref":"#/components/schemas/Localized"},"color":{"$ref":"#/components/schemas/Localized"},"size":{"type":"string"},"price":{"type":"integer"},"qty":{"type":"integer"},"img":{"type":"string","nullable":true}}},"OrderRow":{"type":"object","properties":{"number":{"type":"string","example":"ML261021-4068"},"createdAt":{"type":"string","format":"date-time"},"customerName":{"type":"string"},"customerPhone":{"type":"string"},"gov":{"type":"string"},"total":{"type":"integer"},"paymentMethod":{"type":"string","enum":["cod","instapay","vfcash"]},"paymentStatus":{"type":"string","enum":["pending","pending_verification","paid","rejected","refunded"]},"paymentRef":{"type":"string","nullable":true},"paymentProofUrl":{"type":"string","nullable":true},"status":{"type":"string","enum":["pending","confirmed","processing","ready","shipped","out","delivered","cancelled","returned"]},"itemCount":{"type":"integer"}}},"OrderDetail":{"allOf":[{"$ref":"#/components/schemas/OrderRow"},{"type":"object","properties":{"customerEmail":{"type":"string","nullable":true},"customerId":{"type":"integer","nullable":true},"address":{"$ref":"#/components/schemas/Address"},"items":{"type":"array","items":{"$ref":"#/components/schemas/OrderItem"}},"subtotal":{"type":"integer"},"discount":{"type":"integer"},"coupon":{"type":"string","nullable":true},"shipping":{"type":"integer"},"payment":{"type":"object","properties":{"method":{"type":"string"},"status":{"type":"string"},"ref":{"type":"string","nullable":true},"proofUrl":{"type":"string","nullable":true},"reason":{"type":"string","nullable":true},"verifiedBy":{"type":"string","nullable":true},"verifiedAt":{"type":"string","format":"date-time","nullable":true}}},"next":{"type":"array","items":{"type":"string","description":"Statuses this order may move to"}},"notes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"text":{"type":"string"},"by":{"type":"string","nullable":true},"at":{"type":"string","format":"date-time"}}}},"history":{"type":"array","items":{"type":"object","properties":{"status":{"type":"string"},"by":{"type":"string"},"actorType":{"type":"string"},"note":{"type":"string","nullable":true},"at":{"type":"string","format":"date-time"}}}}}}]},"CustomerOrder":{"type":"object","properties":{"number":{"type":"string"},"status":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"customer":{"type":"object","properties":{"name":{"type":"string"},"phone":{"type":"string"},"email":{"type":"string","nullable":true}}},"address":{"$ref":"#/components/schemas/Address"},"items":{"type":"array","items":{"$ref":"#/components/schemas/OrderItem"}},"subtotal":{"type":"integer"},"discount":{"type":"integer"},"coupon":{"type":"string","nullable":true},"shipping":{"type":"integer"},"total":{"type":"integer"},"payment":{"type":"object","properties":{"method":{"type":"string"},"status":{"type":"string"},"ref":{"type":"string","nullable":true}}},"history":{"type":"array","items":{"type":"object","properties":{"status":{"type":"string"},"at":{"type":"string","format":"date-time"}}}},"canCancel":{"type":"boolean"}}},"CartLine":{"type":"object","properties":{"sku":{"type":"string","example":"ML-STO-BLU-M"},"qty":{"type":"integer","minimum":1,"example":1}},"required":["sku","qty"]},"Quote":{"type":"object","properties":{"lines":{"type":"array","items":{"type":"object","properties":{"sku":{"type":"string"},"qty":{"type":"integer"},"price":{"type":"integer"},"available":{"type":"boolean"},"issue":{"type":"string","nullable":true},"stock":{"type":"integer"},"name":{"$ref":"#/components/schemas/Localized"},"color":{"$ref":"#/components/schemas/Localized"},"size":{"type":"string"},"img":{"type":"string","nullable":true}}}},"count":{"type":"integer"},"subtotal":{"type":"integer"},"discount":{"type":"integer"},"coupon":{"type":"string","nullable":true},"couponError":{"$ref":"#/components/schemas/Localized","nullable":true},"shipping":{"type":"integer","description":"null until a governorate is chosen","nullable":true},"freeShip":{"type":"integer"},"freeLeft":{"type":"integer"},"total":{"type":"integer"},"issues":{"type":"array","items":{"type":"object","properties":{"sku":{"type":"string"},"issue":{"type":"string"},"stock":{"type":"integer"}}}}}},"CheckoutBody":{"type":"object","properties":{"lines":{"type":"array","items":{"$ref":"#/components/schemas/CartLine"}},"address":{"type":"object","properties":{"name":{"type":"string","minLength":3},"phone":{"type":"string","pattern":"^01[0125][0-9]{8}$","example":"01012345678"},"email":{"type":"string"},"gov":{"type":"string","example":"cairo"},"area":{"type":"string"},"street":{"type":"string"},"building":{"type":"string"},"floor":{"type":"string"},"apt":{"type":"string"},"notes":{"type":"string"}},"required":["name","phone","gov","area","street","building"]},"method":{"type":"string","enum":["cod","instapay","vfcash"],"description":"Must be switched on in settings"},"ref":{"type":"string","description":"Transfer reference, ≥ 6 chars (instapay / vfcash)"},"coupon":{"type":"string"},"saveAddress":{"type":"boolean","default":true}},"required":["lines","address","method"]},"Customer":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"newsletter":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"addresses":{"type":"array","items":{"$ref":"#/components/schemas/CustomerAddress"}}}},"CustomerAddress":{"type":"object","properties":{"id":{"type":"integer"},"label":{"type":"string","example":"Home"},"gov":{"type":"string"},"area":{"type":"string"},"street":{"type":"string"},"building":{"type":"string"},"floor":{"type":"string","nullable":true},"apt":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true}}},"CustomerSummary":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":"string","nullable":true},"phone":{"type":"string"},"orders":{"type":"integer"},"spent":{"type":"integer","description":"Paid, non-cancelled orders"},"registered":{"type":"boolean"},"lastOrderAt":{"type":"string","format":"date-time","nullable":true},"since":{"type":"string","format":"date-time"}}},"Settings":{"type":"object","properties":{"instapay":{"type":"object","properties":{"handle":{"type":"string","example":"missleen@instapay"},"name":{"type":"string"}}},"vfcash":{"type":"object","properties":{"number":{"type":"string"},"name":{"type":"string"}}},"freeShip":{"type":"integer","example":2000},"lowStock":{"type":"integer","example":3},"methods":{"type":"object","properties":{"cod":{"type":"boolean"},"instapay":{"type":"boolean"},"vfcash":{"type":"boolean"}}},"ship":{"type":"object","additionalProperties":{"type":"object","properties":{"fee":{"type":"integer"},"on":{"type":"boolean"}}},"description":"Per-governorate overrides keyed by governorate id"},"pairs":{"type":"array","items":{"type":"array","items":{"type":"integer"}}}}},"Governorate":{"type":"object","properties":{"id":{"type":"string","example":"cairo"},"name":{"$ref":"#/components/schemas/Localized"},"fee":{"type":"integer"},"eta":{"type":"string","example":"1–2"},"on":{"type":"boolean"}}},"Task":{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":"string"},"description":{"type":"string","nullable":true},"priority":{"type":"string","enum":["low","medium","high","urgent"]},"status":{"type":"string","enum":["todo","doing","review","done","cancelled"]},"dueAt":{"type":"string","format":"date-time"},"assignees":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"}}}},"createdBy":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"}},"nullable":true},"commentCount":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"comments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"text":{"type":"string"},"isSystem":{"type":"boolean"},"by":{"type":"string","nullable":true},"at":{"type":"string","format":"date-time"}}}}}},"Notification":{"type":"object","properties":{"id":{"type":"integer"},"type":{"type":"string","enum":["order","payment","stock","task"]},"title":{"$ref":"#/components/schemas/Localized"},"ref":{"type":"string","nullable":true},"at":{"type":"string","format":"date-time"},"read":{"type":"boolean"}}},"AuditLog":{"type":"object","properties":{"id":{"type":"integer"},"actorType":{"type":"string"},"actorId":{"type":"integer","nullable":true},"actorName":{"type":"string","nullable":true},"action":{"type":"string","example":"order.status"},"resource":{"type":"string"},"resourceId":{"type":"string","nullable":true},"detail":{"type":"string","nullable":true},"ip":{"type":"string","nullable":true},"userAgent":{"type":"string","nullable":true},"requestId":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"Overview":{"type":"object","properties":{"range":{"type":"integer"},"kpis":{"type":"object","properties":{"revenue":{"type":"integer"},"orders":{"type":"integer"},"pending":{"type":"integer"},"awaiting":{"type":"integer"},"delivered":{"type":"integer"},"cancelled":{"type":"integer"},"toVerify":{"type":"integer"},"aov":{"type":"number"},"customers":{"type":"integer"}}},"series":{"type":"array","items":{"type":"object","properties":{"t":{"type":"string","format":"date-time"},"v":{"type":"integer"},"c":{"type":"integer"}}}},"byMethod":{"type":"object","properties":{"cod":{"type":"integer"},"instapay":{"type":"integer"},"vfcash":{"type":"integer"}}},"byCategory":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"name":{"$ref":"#/components/schemas/Localized"},"value":{"type":"integer"}}}},"best":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"name":{"$ref":"#/components/schemas/Localized"},"qty":{"type":"integer"},"img":{"type":"string","nullable":true}}}},"low":{"type":"array","items":{"type":"object","properties":{"sku":{"type":"string"},"stock":{"type":"integer"},"name":{"$ref":"#/components/schemas/Localized"}}}},"myTasks":{"type":"array","items":{"$ref":"#/components/schemas/Task"}},"recent":{"type":"array","items":{"$ref":"#/components/schemas/OrderRow"}}}},"Employee":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"phone":{"type":"string"},"gender":{"type":"string","enum":["male","female"]},"daily_wage":{"type":"number"},"hour_wage":{"type":"number","description":"null → daily_wage ÷ 8","nullable":true},"department":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true},"is_active":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"EmployeeBody":{"type":"object","properties":{"name":{"type":"string"},"phone":{"type":"string"},"gender":{"type":"string","enum":["male","female"]},"daily_wage":{"type":"number"},"hour_wage":{"type":"number","nullable":true},"department":{"type":"string"},"notes":{"type":"string"}},"required":["name","phone","gender","daily_wage"]},"Attendance":{"type":"object","properties":{"id":{"type":"integer"},"employee_id":{"type":"integer"},"employee_name":{"type":"string"},"gender":{"type":"string"},"department":{"type":"string","nullable":true},"daily_wage":{"type":"number"},"date":{"type":"string","format":"date"},"month":{"type":"string","example":"2026-10"},"status":{"type":"string","enum":["present","absent","leave"]},"day_fraction":{"type":"number","description":"1 = full day; < 1 = partial absence"},"notes":{"type":"string","nullable":true},"recorded_by":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"SalaryRecord":{"type":"object","properties":{"id":{"type":"integer"},"employee_id":{"type":"integer"},"employee_name":{"type":"string"},"gender":{"type":"string"},"department":{"type":"string","nullable":true},"month":{"type":"string"},"working_days":{"type":"integer"},"absent_days":{"type":"number"},"extra_hours":{"type":"number"},"extra_hour_rate":{"type":"number"},"friday_days":{"type":"number"},"daily_wage":{"type":"number"},"base_salary":{"type":"number"},"friday_pay":{"type":"number"},"absence_deduction":{"type":"number"},"extra_pay":{"type":"number"},"errand_count":{"type":"number"},"errand_deduction":{"type":"number"},"early_leave_hours":{"type":"number"},"early_leave_deduction":{"type":"number"},"cash_advance":{"type":"number"},"net_salary":{"type":"number"},"notes":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"SalaryBody":{"type":"object","properties":{"employee_id":{"type":"integer","description":"Create only"},"month":{"type":"string","example":"2026-10","description":"Create only"},"absent_days":{"type":"number"},"extra_hours":{"type":"number"},"friday_days":{"type":"number"},"cash_advance":{"type":"number"},"errand_count":{"type":"number"},"early_leave_hours":{"type":"number"},"notes":{"type":"string"}}},"CashAdvance":{"type":"object","properties":{"id":{"type":"integer"},"employee_id":{"type":"integer"},"employee_name":{"type":"string"},"amount":{"type":"number"},"month":{"type":"string"},"date":{"type":"string"},"reason":{"type":"string","nullable":true},"created_by":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"CashAdvanceBody":{"type":"object","properties":{"employee_id":{"type":"integer","description":"Create only"},"amount":{"type":"number"},"month":{"type":"string","example":"2026-10"},"date":{"type":"string","format":"date"},"reason":{"type":"string"}},"required":["amount","month"]},"Leave":{"type":"object","properties":{"id":{"type":"integer"},"employee_id":{"type":"integer"},"employee_name":{"type":"string"},"month":{"type":"string"},"date":{"type":"string"},"type":{"type":"string","enum":["errand","early_leave"]},"hours":{"type":"number","nullable":true},"deduction":{"type":"number"},"notes":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"LeaveBody":{"type":"object","properties":{"employee_id":{"type":"integer","description":"Create only"},"month":{"type":"string","description":"Create only"},"date":{"type":"string","format":"date"},"type":{"type":"string","enum":["errand","early_leave"]},"hours":{"type":"number","description":"early_leave only"},"notes":{"type":"string"}},"required":["date","type"]},"LedgerParty":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"type":{"type":"string","enum":["debtor","creditor"]},"phone":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true},"is_active":{"type":"integer"},"balance":{"type":"number","description":"debits − payments"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"LedgerTransaction":{"type":"object","properties":{"id":{"type":"integer"},"party_id":{"type":"integer"},"party_name":{"type":"string"},"party_type":{"type":"string"},"type":{"type":"string","enum":["debit","payment"]},"amount":{"type":"number"},"date":{"type":"string","format":"date"},"description":{"type":"string","nullable":true},"created_by":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}}}}}