{
  "openapi": "3.0.3",
  "info": {
    "title": "Exchange Accounting API",
    "version": "4.3.0",
    "description": "Optional previews, automatic allocations, receipts, CSV exports and private presets. Dynamic reports use data/meta/summary/columns. Decimal amounts are strings. EUR is reporting base."
  },
  "servers": [
    {
      "url": "/"
    }
  ],
  "paths": {
    "/health": {
      "get": {
        "tags": [
          "System"
        ],
        "summary": "Liveness (no database dependency)",
        "description": "\n\nRoles: Public",
        "security": [],
        "parameters": [],
        "responses": {
          "200": {
            "description": "{ status: ok }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "{ status: ok }"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/ready": {
      "get": {
        "tags": [
          "System"
        ],
        "summary": "Database readiness",
        "description": "\n\nRoles: Public",
        "security": [],
        "parameters": [],
        "responses": {
          "200": {
            "description": "{ status: ready }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "{ status: ready }"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/login": {
      "post": {
        "tags": [
          "auth"
        ],
        "summary": "Login",
        "description": "\n\nRoles: Public",
        "security": [],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "maxLength": 190
                  },
                  "password": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 128
                  }
                },
                "required": [
                  "email",
                  "password"
                ],
                "additionalProperties": false
              },
              "example": {
                "email": "admin@example.com",
                "password": "YourConfiguredPassword"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ token, expiresAt, user: { id, name, email, role, active, createdAt } }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "token": {
                          "type": "string"
                        },
                        "expiresAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "user": {
                          "$ref": "#/components/schemas/User"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/me": {
      "get": {
        "tags": [
          "auth"
        ],
        "summary": "Current user",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "User without passwordHash",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/User"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/logout": {
      "post": {
        "tags": [
          "auth"
        ],
        "summary": "Revoke current session",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "{ loggedOut: true }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "{ loggedOut: true }"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/logout-all": {
      "post": {
        "tags": [
          "auth"
        ],
        "summary": "Revoke all my sessions",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "{ loggedOut: true }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "{ loggedOut: true }"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/change-password": {
      "post": {
        "tags": [
          "auth"
        ],
        "summary": "Change password and revoke all sessions",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "currentPassword": {
                    "type": "string",
                    "maxLength": 128
                  },
                  "newPassword": {
                    "type": "string",
                    "minLength": 12,
                    "maxLength": 128
                  }
                },
                "required": [
                  "currentPassword",
                  "newPassword"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ loginRequired: true }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "{ loginRequired: true }"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/users": {
      "get": {
        "tags": [
          "users"
        ],
        "summary": "List users",
        "description": "\n\nRoles: ADMIN",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 1000,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 100,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Array of safe user objects",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "Array of safe user objects"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "users"
        ],
        "summary": "Create user",
        "description": "\n\nRoles: ADMIN",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 120
                  },
                  "email": {
                    "type": "string",
                    "format": "email",
                    "maxLength": 190
                  },
                  "password": {
                    "type": "string",
                    "minLength": 12,
                    "maxLength": 128
                  },
                  "role": {
                    "type": "string",
                    "enum": [
                      "ADMIN",
                      "CASHIER",
                      "VIEWER"
                    ]
                  }
                },
                "required": [
                  "name",
                  "email",
                  "password",
                  "role"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "User without passwordHash",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/User"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/users/{id}": {
      "patch": {
        "tags": [
          "users"
        ],
        "summary": "Edit user; self role/deactivation forbidden",
        "description": "\n\nRoles: ADMIN",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 2147483647
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 120
                  },
                  "role": {
                    "type": "string",
                    "enum": [
                      "ADMIN",
                      "CASHIER",
                      "VIEWER"
                    ]
                  },
                  "active": {
                    "type": "boolean"
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "User without passwordHash",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/User"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/users/{id}/reset-password": {
      "post": {
        "tags": [
          "users"
        ],
        "summary": "Admin password reset; revoke sessions",
        "description": "\n\nRoles: ADMIN",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 2147483647
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "newPassword": {
                    "type": "string",
                    "minLength": 12,
                    "maxLength": 128
                  }
                },
                "required": [
                  "newPassword"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ updated: true }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "{ updated: true }"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/customers": {
      "get": {
        "tags": [
          "customers"
        ],
        "summary": "Search customers",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 1000,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 150
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ items: Customer[], total, page, limit }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Customer"
                          }
                        },
                        "total": {
                          "type": "integer"
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "customers"
        ],
        "summary": "Create customer",
        "description": "\n\nRoles: ADMIN, CASHIER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "code": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 40
                  },
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 150
                  },
                  "phone": {
                    "type": "string",
                    "maxLength": 40,
                    "nullable": true
                  },
                  "notes": {
                    "type": "string",
                    "maxLength": 2000,
                    "nullable": true
                  },
                  "active": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "code",
                  "name"
                ],
                "additionalProperties": false
              },
              "example": {
                "code": "C001",
                "name": "Ahmad",
                "phone": "+93700000000"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Customer",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Customer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/customers/{id}": {
      "get": {
        "tags": [
          "customers"
        ],
        "summary": "Customer detail",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 2147483647
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Customer",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Customer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "customers"
        ],
        "summary": "Edit or deactivate customer",
        "description": "\n\nRoles: ADMIN, CASHIER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 2147483647
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "code": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 40
                  },
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 150
                  },
                  "phone": {
                    "type": "string",
                    "maxLength": 40,
                    "nullable": true
                  },
                  "notes": {
                    "type": "string",
                    "maxLength": 2000,
                    "nullable": true
                  },
                  "active": {
                    "type": "boolean"
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Customer",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Customer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/customers/{id}/balances": {
      "get": {
        "tags": [
          "customers"
        ],
        "summary": "Current customer debt/credit by currency",
        "description": "Positive amount: customer owes exchange. Negative: exchange owes customer. EUR equivalent uses current saved rate; null if missing.\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 2147483647
            }
          }
        ],
        "responses": {
          "200": {
            "description": "[{ customerId, currencyCode, amount, side, eurEquivalent, eurRate, rateUpdatedAt }]",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "[{ customerId, currencyCode, amount, side, eurEquivalent, eurRate, rateUpdatedAt }]"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/customers/{id}/statement": {
      "get": {
        "tags": [
          "customers"
        ],
        "summary": "Customer ledger with opening and running balances",
        "description": "Ordered ascending by ledger ID; from inclusive, to exclusive UTC. runningBalances include entries before page and from. Reversals stay visible.\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 2147483647
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 1000,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ items: (LedgerEntry & { runningBalance })[], page, limit, openingBeforePeriod: grouped balances, total }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "{ items: (LedgerEntry & { runningBalance })[], page, limit, openingBeforePeriod: grouped balances, total }"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/customers/{id}/profit": {
      "get": {
        "tags": [
          "customers"
        ],
        "summary": "Profit attributable to customer",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 2147483647
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ProfitSummary",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ProfitSummary"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/customers/{id}/opening-balances": {
      "post": {
        "tags": [
          "customers"
        ],
        "summary": "Set optional initial customer debt/credit once per currency",
        "description": "Positive amount means customer owes exchange. Allowed only before any ledger entries for that customer/currency. Not cash inventory.\n\nRoles: ADMIN",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 2147483647
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "currencyCode": {
                    "type": "string",
                    "pattern": "^[A-Z]{3}$"
                  },
                  "amount": {
                    "type": "string",
                    "pattern": "^-?(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                  },
                  "eurRate": {
                    "type": "string",
                    "pattern": "^(0|[1-9]\\d{0,11})(\\.\\d{1,12})?$"
                  }
                },
                "required": [
                  "currencyCode",
                  "amount"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OpeningBalance",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/OpeningBalance"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/currencies": {
      "get": {
        "tags": [
          "currencies"
        ],
        "summary": "List currencies and reporting rates",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Currency[]",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Currency"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "currencies"
        ],
        "summary": "Create currency",
        "description": "\n\nRoles: ADMIN",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "code": {
                    "type": "string",
                    "pattern": "^[A-Z]{3}$"
                  },
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 80
                  },
                  "decimals": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 8,
                    "default": 2
                  },
                  "eurRate": {
                    "type": "string",
                    "pattern": "^(0|[1-9]\\d{0,11})(\\.\\d{1,12})?$"
                  }
                },
                "required": [
                  "code",
                  "name"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Currency",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Currency"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/currencies/{code}": {
      "patch": {
        "tags": [
          "currencies"
        ],
        "summary": "Edit currency name/active flag",
        "description": "\n\nRoles: ADMIN",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Z]{3}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 80
                  },
                  "active": {
                    "type": "boolean"
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Currency",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Currency"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/currencies/{code}/rate": {
      "put": {
        "tags": [
          "currencies"
        ],
        "summary": "Set reporting rate: EUR per 1 unit of currency",
        "description": "Existing document snapshots do not change. Current balance valuations do change.\n\nRoles: ADMIN, CASHIER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Z]{3}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "eurRate": {
                    "type": "string",
                    "pattern": "^(0|[1-9]\\d{0,11})(\\.\\d{1,12})?$"
                  }
                },
                "required": [
                  "eurRate"
                ],
                "additionalProperties": false
              },
              "example": {
                "eurRate": "0.92"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Currency",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Currency"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/settings": {
      "get": {
        "tags": [
          "settings"
        ],
        "summary": "Read settings",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "{ id, defaultFeePercent, cashEnabled, updatedAt, baseCurrency }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "{ id, defaultFeePercent, cashEnabled, updatedAt, baseCurrency }"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "settings"
        ],
        "summary": "Update fee default and optional cash reporting",
        "description": "\n\nRoles: ADMIN",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "defaultFeePercent": {
                    "type": "string",
                    "pattern": "^(0|[1-9]\\d{0,2})(\\.\\d{1,4})?$"
                  },
                  "cashEnabled": {
                    "type": "boolean"
                  },
                  "staleRateHours": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 720
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Setting",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Setting"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/trades": {
      "get": {
        "tags": [
          "trades"
        ],
        "summary": "List trades",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 1000,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "customerId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 2147483647
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "POSTED",
                "VOID"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ items, total, page, limit }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Trade"
                          }
                        },
                        "total": {
                          "type": "integer"
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "trades"
        ],
        "summary": "Create trade",
        "description": "Creates obligations, NOT cash movements. Fee is added in received currency. paidAmount = receivedAmount × agreedRate rounded to paid currency precision. costBasisEur is optional total historical cost of the paid asset.\n\nRoles: ADMIN, CASHIER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 100
            },
            "example": "example-key-0001"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "customerId": {
                    "type": "integer",
                    "exclusiveMinimum": true,
                    "minimum": 0,
                    "maximum": 2147483647
                  },
                  "receivedCurrency": {
                    "type": "string",
                    "pattern": "^[A-Z]{3}$"
                  },
                  "paidCurrency": {
                    "type": "string",
                    "pattern": "^[A-Z]{3}$"
                  },
                  "receivedAmount": {
                    "type": "string",
                    "pattern": "^(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                  },
                  "agreedRate": {
                    "type": "string",
                    "pattern": "^(0|[1-9]\\d{0,11})(\\.\\d{1,12})?$"
                  },
                  "receivedEurRate": {
                    "type": "string",
                    "pattern": "^(0|[1-9]\\d{0,11})(\\.\\d{1,12})?$"
                  },
                  "paidEurRate": {
                    "type": "string",
                    "pattern": "^(0|[1-9]\\d{0,11})(\\.\\d{1,12})?$"
                  },
                  "feePercent": {
                    "type": "string",
                    "pattern": "^(0|[1-9]\\d{0,2})(\\.\\d{1,4})?$"
                  },
                  "costBasisEur": {
                    "type": "string",
                    "pattern": "^(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                  },
                  "notes": {
                    "type": "string",
                    "maxLength": 2000
                  },
                  "previewId": {
                    "type": "string",
                    "format": "uuid"
                  }
                },
                "required": [
                  "customerId",
                  "receivedCurrency",
                  "paidCurrency",
                  "receivedAmount",
                  "agreedRate"
                ],
                "additionalProperties": false
              },
              "example": {
                "customerId": 1,
                "receivedCurrency": "USD",
                "paidCurrency": "EUR",
                "receivedAmount": "1000",
                "agreedRate": "0.91",
                "receivedEurRate": "0.92",
                "feePercent": "0.5"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "trade",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Trade"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/trades/{id}": {
      "get": {
        "tags": [
          "trades"
        ],
        "summary": "Get trade with ledger entries",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "trade with entries[]",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/Trade"
                        },
                        {
                          "type": "object",
                          "properties": {
                            "entries": {
                              "type": "array",
                              "items": {
                                "$ref": "#/components/schemas/LedgerEntry"
                              }
                            }
                          }
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/trades/{id}/void": {
      "post": {
        "tags": [
          "trades"
        ],
        "summary": "Void trade with reversal entries",
        "description": "No hard delete. Repeat void does not duplicate reversals. Void referenced payments before a trade.\n\nRoles: ADMIN",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 500
                  }
                },
                "required": [
                  "reason"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "trade",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Trade"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/payments": {
      "get": {
        "tags": [
          "payments"
        ],
        "summary": "List payments",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 1000,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "customerId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 2147483647
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "POSTED",
                "VOID"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ items, total, page, limit }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Payment"
                          }
                        },
                        "total": {
                          "type": "integer"
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "payments"
        ],
        "summary": "Create payment",
        "description": "Records actual money movement once. AUTO allocation (default) settles matching open obligations; tradeId restricts AUTO to that trade. NONE keeps it unallocated. Currency/direction must match the reference. Overpayment stays on the customer account. Creation snapshots are historical.\n\nRoles: ADMIN, CASHIER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 100
            },
            "example": "example-key-0001"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "customerId": {
                    "type": "integer",
                    "exclusiveMinimum": true,
                    "minimum": 0,
                    "maximum": 2147483647
                  },
                  "tradeId": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "currencyCode": {
                    "type": "string",
                    "pattern": "^[A-Z]{3}$"
                  },
                  "direction": {
                    "type": "string",
                    "enum": [
                      "RECEIVE",
                      "PAY"
                    ]
                  },
                  "amount": {
                    "type": "string",
                    "pattern": "^(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                  },
                  "eurRate": {
                    "type": "string",
                    "pattern": "^(0|[1-9]\\d{0,11})(\\.\\d{1,12})?$"
                  },
                  "notes": {
                    "type": "string",
                    "maxLength": 2000
                  },
                  "allocationMode": {
                    "type": "string",
                    "enum": [
                      "AUTO",
                      "NONE"
                    ],
                    "default": "AUTO"
                  }
                },
                "required": [
                  "customerId",
                  "currencyCode",
                  "direction",
                  "amount"
                ],
                "additionalProperties": false
              },
              "example": {
                "customerId": 1,
                "currencyCode": "USD",
                "direction": "RECEIVE",
                "amount": "1005",
                "eurRate": "0.92"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "payment",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Payment"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/payments/{id}": {
      "get": {
        "tags": [
          "payments"
        ],
        "summary": "Get payment with ledger entries",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "payment with entries[]",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/Payment"
                        },
                        {
                          "type": "object",
                          "properties": {
                            "entries": {
                              "type": "array",
                              "items": {
                                "$ref": "#/components/schemas/LedgerEntry"
                              }
                            }
                          }
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/payments/{id}/void": {
      "post": {
        "tags": [
          "payments"
        ],
        "summary": "Void payment with reversal entries",
        "description": "No hard delete. Repeat void does not duplicate reversals. Void referenced payments before a trade.\n\nRoles: ADMIN",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 500
                  }
                },
                "required": [
                  "reason"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "payment",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Payment"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/reports/profit": {
      "get": {
        "tags": [
          "reports"
        ],
        "summary": "Aggregate accrued profit report",
        "description": "feeRevenueEur includes all posted trade fees; knownExchangeProfitEur includes only known cost basis. totalProfitEur is null if any trade profit is unknown. No operating expenses included.\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "customerId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 2147483647
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ProfitSummary",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ProfitSummary"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/reports/customer-profit": {
      "get": {
        "tags": [
          "reports"
        ],
        "summary": "Paged customer profit breakdown",
        "description": "Customer ID order, not a profit ranking.\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 1000,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "[{ customer, profit: ProfitSummary }]",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "[{ customer, profit: ProfitSummary }]"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "reports"
        ],
        "summary": "سود مشتریان با فیلتر و صفحه‌بندی",
        "description": "Read-only POST. No idempotency key needed. Decimal strings, UTC dates, from inclusive and to/asOf exclusive. Options endpoint describes accepted fields. All staff roles may view financial data. Unknown filters/fields are rejected. Rows, total count and summaries share a database snapshot.\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "search": {
                    "type": "string",
                    "maxLength": 150,
                    "default": ""
                  },
                  "filters": {
                    "type": "object",
                    "properties": {
                      "customerId": {
                        "type": "integer",
                        "exclusiveMinimum": true,
                        "minimum": 0,
                        "maximum": 2147483647
                      },
                      "currency": {
                        "type": "string",
                        "pattern": "^[A-Z]{3}$"
                      },
                      "from": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "to": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "customerActive": {
                        "type": "boolean"
                      }
                    },
                    "additionalProperties": false,
                    "default": {}
                  },
                  "fields": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "customerId",
                        "customerName",
                        "customerCode",
                        "customerPhone",
                        "tradeCount",
                        "feeRevenueEur",
                        "knownExchangeProfitEur",
                        "knownSubtotalEur",
                        "unknownProfitTrades",
                        "totalProfitEur"
                      ]
                    },
                    "minItems": 1,
                    "maxItems": 10,
                    "default": [
                      "customerId",
                      "customerName",
                      "tradeCount",
                      "feeRevenueEur",
                      "knownExchangeProfitEur",
                      "unknownProfitTrades",
                      "totalProfitEur"
                    ]
                  },
                  "sort": {
                    "type": "object",
                    "properties": {
                      "field": {
                        "type": "string",
                        "enum": [
                          "customerId",
                          "customerName",
                          "customerCode",
                          "customerPhone",
                          "tradeCount",
                          "feeRevenueEur",
                          "knownExchangeProfitEur",
                          "knownSubtotalEur",
                          "unknownProfitTrades",
                          "totalProfitEur"
                        ]
                      },
                      "direction": {
                        "type": "string",
                        "enum": [
                          "asc",
                          "desc"
                        ]
                      }
                    },
                    "required": [
                      "field",
                      "direction"
                    ],
                    "additionalProperties": false,
                    "default": {
                      "field": "feeRevenueEur",
                      "direction": "desc"
                    }
                  },
                  "page": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10000,
                    "default": 1
                  },
                  "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100,
                    "default": 25
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "search": "",
                "filters": {
                  "from": "2026-09-01T00:00:00Z",
                  "to": "2026-10-01T00:00:00Z"
                },
                "fields": [
                  "customerId",
                  "customerName",
                  "tradeCount",
                  "feeRevenueEur",
                  "knownExchangeProfitEur",
                  "unknownProfitTrades",
                  "totalProfitEur"
                ],
                "sort": {
                  "field": "feeRevenueEur",
                  "direction": "desc"
                },
                "page": 1,
                "limit": 25
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "ReportEnvelope",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta",
                    "summary",
                    "columns"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": {
                          "oneOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "number"
                            },
                            {
                              "type": "boolean"
                            }
                          ],
                          "nullable": true
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "report",
                        "page",
                        "limit",
                        "totalItems",
                        "totalPages",
                        "hasNextPage",
                        "hasPreviousPage",
                        "baseCurrency",
                        "timezone"
                      ],
                      "properties": {
                        "report": {
                          "type": "string"
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        },
                        "totalItems": {
                          "type": "integer"
                        },
                        "totalPages": {
                          "type": "integer"
                        },
                        "hasNextPage": {
                          "type": "boolean"
                        },
                        "hasPreviousPage": {
                          "type": "boolean"
                        },
                        "outOfRange": {
                          "type": "boolean"
                        },
                        "baseCurrency": {
                          "type": "string",
                          "enum": [
                            "EUR"
                          ]
                        },
                        "timezone": {
                          "type": "string",
                          "enum": [
                            "UTC"
                          ]
                        },
                        "generatedAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "filters": {
                          "type": "object"
                        },
                        "search": {
                          "type": "string"
                        },
                        "sort": {
                          "type": "object"
                        },
                        "fields": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "valuation": {
                          "type": "string"
                        }
                      }
                    },
                    "summary": {
                      "type": "object",
                      "description": "All filtered results, never just this page. Financial totals exclude VOID. Monetary values are strings; unknown profit is null.",
                      "additionalProperties": true
                    },
                    "columns": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "key",
                          "label",
                          "type"
                        ],
                        "properties": {
                          "key": {
                            "type": "string"
                          },
                          "label": {
                            "type": "string"
                          },
                          "type": {
                            "type": "string"
                          },
                          "sortable": {
                            "type": "boolean"
                          },
                          "currency": {
                            "type": "string"
                          },
                          "currencyField": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/reports/balances": {
      "get": {
        "tags": [
          "reports"
        ],
        "summary": "Paged current customer balances",
        "description": "Pagination applies to customers. Do not net different currencies automatically.\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 1000,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 100,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Array of per-customer per-currency balances",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "Array of per-customer per-currency balances"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "reports"
        ],
        "summary": "مانده بدهی و طلب با فیلتر و صفحه‌بندی",
        "description": "Read-only POST. No idempotency key needed. Decimal strings, UTC dates, from inclusive and to/asOf exclusive. Options endpoint describes accepted fields. All staff roles may view financial data. Unknown filters/fields are rejected. Rows, total count and summaries share a database snapshot.\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "search": {
                    "type": "string",
                    "maxLength": 150,
                    "default": ""
                  },
                  "filters": {
                    "type": "object",
                    "properties": {
                      "customerId": {
                        "type": "integer",
                        "exclusiveMinimum": true,
                        "minimum": 0,
                        "maximum": 2147483647
                      },
                      "currency": {
                        "type": "string",
                        "pattern": "^[A-Z]{3}$"
                      },
                      "customerActive": {
                        "type": "boolean"
                      },
                      "asOf": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "side": {
                        "type": "string",
                        "enum": [
                          "CUSTOMER_OWES",
                          "CUSTOMER_IS_OWED",
                          "SETTLED"
                        ]
                      },
                      "minAmount": {
                        "type": "string",
                        "pattern": "^-?(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                      },
                      "maxAmount": {
                        "type": "string",
                        "pattern": "^-?(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                      }
                    },
                    "additionalProperties": false,
                    "default": {}
                  },
                  "fields": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "customerId",
                        "customerName",
                        "customerCode",
                        "customerPhone",
                        "currencyCode",
                        "amount",
                        "side",
                        "eurEquivalent",
                        "eurRate",
                        "rateStatus",
                        "rateUpdatedAt"
                      ]
                    },
                    "minItems": 1,
                    "maxItems": 11,
                    "default": [
                      "customerId",
                      "customerName",
                      "currencyCode",
                      "amount",
                      "side",
                      "eurEquivalent",
                      "rateStatus",
                      "rateUpdatedAt"
                    ]
                  },
                  "sort": {
                    "type": "object",
                    "properties": {
                      "field": {
                        "type": "string",
                        "enum": [
                          "customerId",
                          "customerName",
                          "customerCode",
                          "customerPhone",
                          "currencyCode",
                          "amount",
                          "side",
                          "eurEquivalent",
                          "eurRate",
                          "rateStatus",
                          "rateUpdatedAt"
                        ]
                      },
                      "direction": {
                        "type": "string",
                        "enum": [
                          "asc",
                          "desc"
                        ]
                      }
                    },
                    "required": [
                      "field",
                      "direction"
                    ],
                    "additionalProperties": false,
                    "default": {
                      "field": "customerId",
                      "direction": "asc"
                    }
                  },
                  "page": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10000,
                    "default": 1
                  },
                  "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100,
                    "default": 25
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "search": "",
                "filters": {},
                "fields": [
                  "customerId",
                  "customerName",
                  "currencyCode",
                  "amount",
                  "side",
                  "eurEquivalent",
                  "rateStatus",
                  "rateUpdatedAt"
                ],
                "sort": {
                  "field": "customerId",
                  "direction": "asc"
                },
                "page": 1,
                "limit": 25
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "ReportEnvelope",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta",
                    "summary",
                    "columns"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": {
                          "oneOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "number"
                            },
                            {
                              "type": "boolean"
                            }
                          ],
                          "nullable": true
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "report",
                        "page",
                        "limit",
                        "totalItems",
                        "totalPages",
                        "hasNextPage",
                        "hasPreviousPage",
                        "baseCurrency",
                        "timezone"
                      ],
                      "properties": {
                        "report": {
                          "type": "string"
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        },
                        "totalItems": {
                          "type": "integer"
                        },
                        "totalPages": {
                          "type": "integer"
                        },
                        "hasNextPage": {
                          "type": "boolean"
                        },
                        "hasPreviousPage": {
                          "type": "boolean"
                        },
                        "outOfRange": {
                          "type": "boolean"
                        },
                        "baseCurrency": {
                          "type": "string",
                          "enum": [
                            "EUR"
                          ]
                        },
                        "timezone": {
                          "type": "string",
                          "enum": [
                            "UTC"
                          ]
                        },
                        "generatedAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "filters": {
                          "type": "object"
                        },
                        "search": {
                          "type": "string"
                        },
                        "sort": {
                          "type": "object"
                        },
                        "fields": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "valuation": {
                          "type": "string"
                        }
                      }
                    },
                    "summary": {
                      "type": "object",
                      "description": "All filtered results, never just this page. Financial totals exclude VOID. Monetary values are strings; unknown profit is null.",
                      "additionalProperties": true
                    },
                    "columns": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "key",
                          "label",
                          "type"
                        ],
                        "properties": {
                          "key": {
                            "type": "string"
                          },
                          "label": {
                            "type": "string"
                          },
                          "type": {
                            "type": "string"
                          },
                          "sortable": {
                            "type": "boolean"
                          },
                          "currency": {
                            "type": "string"
                          },
                          "currencyField": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/reports/dashboard": {
      "get": {
        "tags": [
          "reports"
        ],
        "summary": "Dashboard counts, profit and optional cash",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "{ customers, trades, profit: ProfitSummary, cash }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "{ customers, trades, profit: ProfitSummary, cash }"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/cash": {
      "get": {
        "tags": [
          "cash"
        ],
        "summary": "Optional cash balances and completeness",
        "description": "No inventory enforcement. Balance remains null without opening, but net movement is available. Includes only posted payments.\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "{ enabled, balances: [{ currencyCode, opening, netMovement, balance, complete }] }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "{ enabled, balances: [{ currencyCode, opening, netMovement, balance, complete }] }"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/cash/openings": {
      "post": {
        "tags": [
          "cash"
        ],
        "summary": "Record cash balance at system start (optional)",
        "description": "One immutable opening per currency. May be entered later but must describe balance BEFORE all recorded payments. No automatic valuation/cost averaging.\n\nRoles: ADMIN",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "currencyCode": {
                    "type": "string",
                    "pattern": "^[A-Z]{3}$"
                  },
                  "amount": {
                    "type": "string",
                    "pattern": "^(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                  }
                },
                "required": [
                  "currencyCode",
                  "amount"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "CashOpening",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/CashOpening"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/audit-logs": {
      "get": {
        "tags": [
          "audit-logs"
        ],
        "summary": "Read immutable audit history",
        "description": "\n\nRoles: ADMIN",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 1000,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "AuditLog[]",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AuditLog"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/reports/catalog": {
      "get": {
        "tags": [
          "reports"
        ],
        "summary": "فهرست گزارش‌های پویا",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Report names, labels and options URLs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "Report names, labels and options URLs"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/reports/trades/options": {
      "get": {
        "tags": [
          "reports"
        ],
        "summary": "فیلدها و فیلترهای مجاز: معاملات",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "ReportOptions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "ReportOptions"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/reports/trades": {
      "post": {
        "tags": [
          "reports"
        ],
        "summary": "معاملات با فیلتر و صفحه‌بندی",
        "description": "Read-only POST. No idempotency key needed. Decimal strings, UTC dates, from inclusive and to/asOf exclusive. Options endpoint describes accepted fields. All staff roles may view financial data. Unknown filters/fields are rejected. Rows, total count and summaries share a database snapshot.\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "search": {
                    "type": "string",
                    "maxLength": 150,
                    "default": ""
                  },
                  "filters": {
                    "type": "object",
                    "properties": {
                      "customerId": {
                        "type": "integer",
                        "exclusiveMinimum": true,
                        "minimum": 0,
                        "maximum": 2147483647
                      },
                      "currency": {
                        "type": "string",
                        "pattern": "^[A-Z]{3}$"
                      },
                      "from": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "to": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "customerActive": {
                        "type": "boolean"
                      },
                      "status": {
                        "type": "string",
                        "enum": [
                          "POSTED",
                          "VOID"
                        ]
                      },
                      "minAmount": {
                        "type": "string",
                        "pattern": "^-?(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                      },
                      "maxAmount": {
                        "type": "string",
                        "pattern": "^-?(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                      }
                    },
                    "additionalProperties": false,
                    "default": {}
                  },
                  "fields": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "id",
                        "documentNumber",
                        "profitStatus",
                        "customerId",
                        "customerName",
                        "customerCode",
                        "customerPhone",
                        "receivedCurrency",
                        "receivedAmount",
                        "paidCurrency",
                        "paidAmount",
                        "agreedRate",
                        "receivedEurRate",
                        "paidEurRate",
                        "feePercent",
                        "feeAmount",
                        "feeEur",
                        "costBasisEur",
                        "exchangeProfitEur",
                        "status",
                        "createdAt",
                        "notes"
                      ]
                    },
                    "minItems": 1,
                    "maxItems": 22,
                    "default": [
                      "id",
                      "documentNumber",
                      "customerName",
                      "receivedAmount",
                      "receivedCurrency",
                      "paidAmount",
                      "paidCurrency",
                      "feeEur",
                      "exchangeProfitEur",
                      "profitStatus",
                      "status",
                      "createdAt"
                    ]
                  },
                  "sort": {
                    "type": "object",
                    "properties": {
                      "field": {
                        "type": "string",
                        "enum": [
                          "id",
                          "documentNumber",
                          "profitStatus",
                          "customerId",
                          "customerName",
                          "customerCode",
                          "customerPhone",
                          "receivedCurrency",
                          "receivedAmount",
                          "paidCurrency",
                          "paidAmount",
                          "agreedRate",
                          "receivedEurRate",
                          "paidEurRate",
                          "feePercent",
                          "feeAmount",
                          "feeEur",
                          "costBasisEur",
                          "exchangeProfitEur",
                          "status",
                          "createdAt"
                        ]
                      },
                      "direction": {
                        "type": "string",
                        "enum": [
                          "asc",
                          "desc"
                        ]
                      }
                    },
                    "required": [
                      "field",
                      "direction"
                    ],
                    "additionalProperties": false,
                    "default": {
                      "field": "createdAt",
                      "direction": "desc"
                    }
                  },
                  "page": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10000,
                    "default": 1
                  },
                  "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100,
                    "default": 25
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "search": "",
                "filters": {
                  "from": "2026-09-01T00:00:00Z",
                  "to": "2026-10-01T00:00:00Z"
                },
                "fields": [
                  "id",
                  "documentNumber",
                  "customerName",
                  "receivedAmount",
                  "receivedCurrency",
                  "paidAmount",
                  "paidCurrency",
                  "feeEur",
                  "exchangeProfitEur",
                  "profitStatus",
                  "status",
                  "createdAt"
                ],
                "sort": {
                  "field": "createdAt",
                  "direction": "desc"
                },
                "page": 1,
                "limit": 25
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "ReportEnvelope",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta",
                    "summary",
                    "columns"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": {
                          "oneOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "number"
                            },
                            {
                              "type": "boolean"
                            }
                          ],
                          "nullable": true
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "report",
                        "page",
                        "limit",
                        "totalItems",
                        "totalPages",
                        "hasNextPage",
                        "hasPreviousPage",
                        "baseCurrency",
                        "timezone"
                      ],
                      "properties": {
                        "report": {
                          "type": "string"
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        },
                        "totalItems": {
                          "type": "integer"
                        },
                        "totalPages": {
                          "type": "integer"
                        },
                        "hasNextPage": {
                          "type": "boolean"
                        },
                        "hasPreviousPage": {
                          "type": "boolean"
                        },
                        "outOfRange": {
                          "type": "boolean"
                        },
                        "baseCurrency": {
                          "type": "string",
                          "enum": [
                            "EUR"
                          ]
                        },
                        "timezone": {
                          "type": "string",
                          "enum": [
                            "UTC"
                          ]
                        },
                        "generatedAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "filters": {
                          "type": "object"
                        },
                        "search": {
                          "type": "string"
                        },
                        "sort": {
                          "type": "object"
                        },
                        "fields": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "valuation": {
                          "type": "string"
                        }
                      }
                    },
                    "summary": {
                      "type": "object",
                      "description": "All filtered results, never just this page. Financial totals exclude VOID. Monetary values are strings; unknown profit is null.",
                      "additionalProperties": true
                    },
                    "columns": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "key",
                          "label",
                          "type"
                        ],
                        "properties": {
                          "key": {
                            "type": "string"
                          },
                          "label": {
                            "type": "string"
                          },
                          "type": {
                            "type": "string"
                          },
                          "sortable": {
                            "type": "boolean"
                          },
                          "currency": {
                            "type": "string"
                          },
                          "currencyField": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/reports/payments/options": {
      "get": {
        "tags": [
          "reports"
        ],
        "summary": "فیلدها و فیلترهای مجاز: دریافت و پرداخت",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "ReportOptions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "ReportOptions"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/reports/payments": {
      "post": {
        "tags": [
          "reports"
        ],
        "summary": "دریافت و پرداخت با فیلتر و صفحه‌بندی",
        "description": "Read-only POST. No idempotency key needed. Decimal strings, UTC dates, from inclusive and to/asOf exclusive. Options endpoint describes accepted fields. All staff roles may view financial data. Unknown filters/fields are rejected. Rows, total count and summaries share a database snapshot.\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "search": {
                    "type": "string",
                    "maxLength": 150,
                    "default": ""
                  },
                  "filters": {
                    "type": "object",
                    "properties": {
                      "customerId": {
                        "type": "integer",
                        "exclusiveMinimum": true,
                        "minimum": 0,
                        "maximum": 2147483647
                      },
                      "currency": {
                        "type": "string",
                        "pattern": "^[A-Z]{3}$"
                      },
                      "from": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "to": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "customerActive": {
                        "type": "boolean"
                      },
                      "status": {
                        "type": "string",
                        "enum": [
                          "POSTED",
                          "VOID"
                        ]
                      },
                      "direction": {
                        "type": "string",
                        "enum": [
                          "RECEIVE",
                          "PAY"
                        ]
                      },
                      "tradeId": {
                        "type": "string",
                        "format": "uuid"
                      },
                      "minAmount": {
                        "type": "string",
                        "pattern": "^-?(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                      },
                      "maxAmount": {
                        "type": "string",
                        "pattern": "^-?(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                      }
                    },
                    "additionalProperties": false,
                    "default": {}
                  },
                  "fields": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "id",
                        "documentNumber",
                        "unallocatedAmount",
                        "customerId",
                        "customerName",
                        "customerCode",
                        "customerPhone",
                        "tradeId",
                        "currencyCode",
                        "direction",
                        "amount",
                        "eurRate",
                        "eurAmount",
                        "status",
                        "createdAt",
                        "notes"
                      ]
                    },
                    "minItems": 1,
                    "maxItems": 16,
                    "default": [
                      "id",
                      "documentNumber",
                      "customerName",
                      "currencyCode",
                      "direction",
                      "amount",
                      "unallocatedAmount",
                      "eurRate",
                      "status",
                      "createdAt"
                    ]
                  },
                  "sort": {
                    "type": "object",
                    "properties": {
                      "field": {
                        "type": "string",
                        "enum": [
                          "id",
                          "documentNumber",
                          "unallocatedAmount",
                          "customerId",
                          "customerName",
                          "customerCode",
                          "customerPhone",
                          "tradeId",
                          "currencyCode",
                          "direction",
                          "amount",
                          "eurRate",
                          "eurAmount",
                          "status",
                          "createdAt"
                        ]
                      },
                      "direction": {
                        "type": "string",
                        "enum": [
                          "asc",
                          "desc"
                        ]
                      }
                    },
                    "required": [
                      "field",
                      "direction"
                    ],
                    "additionalProperties": false,
                    "default": {
                      "field": "createdAt",
                      "direction": "desc"
                    }
                  },
                  "page": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10000,
                    "default": 1
                  },
                  "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100,
                    "default": 25
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "search": "",
                "filters": {
                  "from": "2026-09-01T00:00:00Z",
                  "to": "2026-10-01T00:00:00Z"
                },
                "fields": [
                  "id",
                  "documentNumber",
                  "customerName",
                  "currencyCode",
                  "direction",
                  "amount",
                  "unallocatedAmount",
                  "eurRate",
                  "status",
                  "createdAt"
                ],
                "sort": {
                  "field": "createdAt",
                  "direction": "desc"
                },
                "page": 1,
                "limit": 25
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "ReportEnvelope",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta",
                    "summary",
                    "columns"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": {
                          "oneOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "number"
                            },
                            {
                              "type": "boolean"
                            }
                          ],
                          "nullable": true
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "report",
                        "page",
                        "limit",
                        "totalItems",
                        "totalPages",
                        "hasNextPage",
                        "hasPreviousPage",
                        "baseCurrency",
                        "timezone"
                      ],
                      "properties": {
                        "report": {
                          "type": "string"
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        },
                        "totalItems": {
                          "type": "integer"
                        },
                        "totalPages": {
                          "type": "integer"
                        },
                        "hasNextPage": {
                          "type": "boolean"
                        },
                        "hasPreviousPage": {
                          "type": "boolean"
                        },
                        "outOfRange": {
                          "type": "boolean"
                        },
                        "baseCurrency": {
                          "type": "string",
                          "enum": [
                            "EUR"
                          ]
                        },
                        "timezone": {
                          "type": "string",
                          "enum": [
                            "UTC"
                          ]
                        },
                        "generatedAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "filters": {
                          "type": "object"
                        },
                        "search": {
                          "type": "string"
                        },
                        "sort": {
                          "type": "object"
                        },
                        "fields": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "valuation": {
                          "type": "string"
                        }
                      }
                    },
                    "summary": {
                      "type": "object",
                      "description": "All filtered results, never just this page. Financial totals exclude VOID. Monetary values are strings; unknown profit is null.",
                      "additionalProperties": true
                    },
                    "columns": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "key",
                          "label",
                          "type"
                        ],
                        "properties": {
                          "key": {
                            "type": "string"
                          },
                          "label": {
                            "type": "string"
                          },
                          "type": {
                            "type": "string"
                          },
                          "sortable": {
                            "type": "boolean"
                          },
                          "currency": {
                            "type": "string"
                          },
                          "currencyField": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/reports/statement/options": {
      "get": {
        "tags": [
          "reports"
        ],
        "summary": "فیلدها و فیلترهای مجاز: گردش حساب",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "ReportOptions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "ReportOptions"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/reports/statement": {
      "post": {
        "tags": [
          "reports"
        ],
        "summary": "گردش حساب با فیلتر و صفحه‌بندی",
        "description": "Read-only POST. No idempotency key needed. Decimal strings, UTC dates, from inclusive and to/asOf exclusive. Options endpoint describes accepted fields. All staff roles may view financial data. Unknown filters/fields are rejected. Rows, total count and summaries share a database snapshot.\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "search": {
                    "type": "string",
                    "maxLength": 150,
                    "default": ""
                  },
                  "filters": {
                    "type": "object",
                    "properties": {
                      "customerId": {
                        "type": "integer",
                        "exclusiveMinimum": true,
                        "minimum": 0,
                        "maximum": 2147483647
                      },
                      "currency": {
                        "type": "string",
                        "pattern": "^[A-Z]{3}$"
                      },
                      "from": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "to": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "customerActive": {
                        "type": "boolean"
                      },
                      "source": {
                        "type": "string",
                        "enum": [
                          "TRADE",
                          "PAYMENT",
                          "OPENING",
                          "REVERSAL"
                        ]
                      },
                      "minAmount": {
                        "type": "string",
                        "pattern": "^-?(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                      },
                      "maxAmount": {
                        "type": "string",
                        "pattern": "^-?(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                      }
                    },
                    "required": [
                      "customerId"
                    ],
                    "additionalProperties": false,
                    "default": {}
                  },
                  "fields": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "id",
                        "customerId",
                        "customerName",
                        "customerCode",
                        "customerPhone",
                        "currencyCode",
                        "amount",
                        "runningBalance",
                        "eurRate",
                        "eurAmount",
                        "source",
                        "tradeId",
                        "paymentId",
                        "openingId",
                        "reversalOf",
                        "createdAt"
                      ]
                    },
                    "minItems": 1,
                    "maxItems": 16,
                    "default": [
                      "id",
                      "customerName",
                      "currencyCode",
                      "amount",
                      "runningBalance",
                      "source",
                      "createdAt"
                    ]
                  },
                  "sort": {
                    "type": "object",
                    "properties": {
                      "field": {
                        "type": "string",
                        "enum": [
                          "id",
                          "customerId",
                          "customerName",
                          "customerCode",
                          "customerPhone",
                          "currencyCode",
                          "amount",
                          "runningBalance",
                          "eurRate",
                          "eurAmount",
                          "source",
                          "tradeId",
                          "paymentId",
                          "openingId",
                          "reversalOf",
                          "createdAt"
                        ]
                      },
                      "direction": {
                        "type": "string",
                        "enum": [
                          "asc",
                          "desc"
                        ]
                      }
                    },
                    "required": [
                      "field",
                      "direction"
                    ],
                    "additionalProperties": false,
                    "default": {
                      "field": "createdAt",
                      "direction": "asc"
                    }
                  },
                  "page": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10000,
                    "default": 1
                  },
                  "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100,
                    "default": 25
                  }
                },
                "required": [
                  "filters"
                ],
                "additionalProperties": false
              },
              "example": {
                "search": "",
                "filters": {
                  "customerId": 1,
                  "from": "2026-09-01T00:00:00Z",
                  "to": "2026-10-01T00:00:00Z"
                },
                "fields": [
                  "id",
                  "customerName",
                  "currencyCode",
                  "amount",
                  "runningBalance",
                  "source",
                  "createdAt"
                ],
                "sort": {
                  "field": "createdAt",
                  "direction": "asc"
                },
                "page": 1,
                "limit": 25
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "ReportEnvelope",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta",
                    "summary",
                    "columns"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": {
                          "oneOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "number"
                            },
                            {
                              "type": "boolean"
                            }
                          ],
                          "nullable": true
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "required": [
                        "report",
                        "page",
                        "limit",
                        "totalItems",
                        "totalPages",
                        "hasNextPage",
                        "hasPreviousPage",
                        "baseCurrency",
                        "timezone"
                      ],
                      "properties": {
                        "report": {
                          "type": "string"
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        },
                        "totalItems": {
                          "type": "integer"
                        },
                        "totalPages": {
                          "type": "integer"
                        },
                        "hasNextPage": {
                          "type": "boolean"
                        },
                        "hasPreviousPage": {
                          "type": "boolean"
                        },
                        "outOfRange": {
                          "type": "boolean"
                        },
                        "baseCurrency": {
                          "type": "string",
                          "enum": [
                            "EUR"
                          ]
                        },
                        "timezone": {
                          "type": "string",
                          "enum": [
                            "UTC"
                          ]
                        },
                        "generatedAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "filters": {
                          "type": "object"
                        },
                        "search": {
                          "type": "string"
                        },
                        "sort": {
                          "type": "object"
                        },
                        "fields": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "valuation": {
                          "type": "string"
                        }
                      }
                    },
                    "summary": {
                      "type": "object",
                      "description": "All filtered results, never just this page. Financial totals exclude VOID. Monetary values are strings; unknown profit is null.",
                      "additionalProperties": true
                    },
                    "columns": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "key",
                          "label",
                          "type"
                        ],
                        "properties": {
                          "key": {
                            "type": "string"
                          },
                          "label": {
                            "type": "string"
                          },
                          "type": {
                            "type": "string"
                          },
                          "sortable": {
                            "type": "boolean"
                          },
                          "currency": {
                            "type": "string"
                          },
                          "currencyField": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/reports/balances/options": {
      "get": {
        "tags": [
          "reports"
        ],
        "summary": "فیلدها و فیلترهای مجاز: مانده بدهی و طلب",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "ReportOptions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "ReportOptions"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/reports/customer-profit/options": {
      "get": {
        "tags": [
          "reports"
        ],
        "summary": "فیلدها و فیلترهای مجاز: سود مشتریان",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "ReportOptions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "ReportOptions"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/trades/preview": {
      "post": {
        "tags": [
          "trades"
        ],
        "summary": "پیش‌نمایش اختیاری معامله",
        "description": "No financial document. Preview expires in 5 minutes. Pass previewId with unchanged input to create; stale/consumed previews return 409. Direct creation is still allowed.\n\nRoles: ADMIN, CASHIER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "customerId": {
                    "type": "integer",
                    "exclusiveMinimum": true,
                    "minimum": 0,
                    "maximum": 2147483647
                  },
                  "receivedCurrency": {
                    "type": "string",
                    "pattern": "^[A-Z]{3}$"
                  },
                  "paidCurrency": {
                    "type": "string",
                    "pattern": "^[A-Z]{3}$"
                  },
                  "receivedAmount": {
                    "type": "string",
                    "pattern": "^(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                  },
                  "agreedRate": {
                    "type": "string",
                    "pattern": "^(0|[1-9]\\d{0,11})(\\.\\d{1,12})?$"
                  },
                  "receivedEurRate": {
                    "type": "string",
                    "pattern": "^(0|[1-9]\\d{0,11})(\\.\\d{1,12})?$"
                  },
                  "paidEurRate": {
                    "type": "string",
                    "pattern": "^(0|[1-9]\\d{0,11})(\\.\\d{1,12})?$"
                  },
                  "feePercent": {
                    "type": "string",
                    "pattern": "^(0|[1-9]\\d{0,2})(\\.\\d{1,4})?$"
                  },
                  "costBasisEur": {
                    "type": "string",
                    "pattern": "^(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                  },
                  "notes": {
                    "type": "string",
                    "maxLength": 2000
                  },
                  "previewId": {
                    "type": "string",
                    "format": "uuid"
                  }
                },
                "required": [
                  "customerId",
                  "receivedCurrency",
                  "paidCurrency",
                  "receivedAmount",
                  "agreedRate"
                ],
                "additionalProperties": false
              },
              "example": {
                "customerId": 1,
                "receivedCurrency": "USD",
                "paidCurrency": "EUR",
                "receivedAmount": "1000",
                "agreedRate": "0.91",
                "receivedEurRate": "0.92",
                "feePercent": "0.5"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Pricing, obligations, warnings, previewId and expiresAt",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "Pricing, obligations, warnings, previewId and expiresAt"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/trades/{id}/settlement": {
      "get": {
        "tags": [
          "trades"
        ],
        "summary": "وضعیت تسویه دو سمت معامله",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ tradeId, documentNumber, state, legs }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "{ tradeId, documentNumber, state, legs }"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/payments/{id}/allocations": {
      "get": {
        "tags": [
          "payments"
        ],
        "summary": "تخصیص‌ها و مانده تخصیص‌نیافته پرداخت",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Payment allocation summary; version required for edits",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "Payment allocation summary; version required for edits"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "payments"
        ],
        "summary": "اصلاح تخصیص بدون تغییر گردش مالی",
        "description": "Replaces all allocations atomically. AUTO targets oldest open matching obligations (up to 100; tradeId if present restricts it); NONE clears allocations; MANUAL uses supplied rows. It never creates money movements.\n\nRoles: ADMIN, CASHIER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "expectedVersion": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "AUTO",
                      "MANUAL",
                      "NONE"
                    ],
                    "default": "MANUAL"
                  },
                  "allocations": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "tradeId": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "amount": {
                          "type": "string",
                          "pattern": "^(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                        }
                      },
                      "required": [
                        "tradeId",
                        "amount"
                      ],
                      "additionalProperties": false
                    },
                    "maxItems": 100,
                    "default": []
                  }
                },
                "required": [
                  "expectedVersion"
                ],
                "additionalProperties": false
              },
              "example": {
                "expectedVersion": 1,
                "mode": "AUTO",
                "allocations": []
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Payment allocation summary",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "Payment allocation summary"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/trades/{id}/receipt": {
      "get": {
        "tags": [
          "trades"
        ],
        "summary": "رسید trade",
        "description": "format=json by default; html is escaped and printable. Current settlement plus historical balance-at-posting; legacy documents use UUID as reference.\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "html"
              ],
              "default": "json"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Receipt JSON or printable HTML",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "Receipt JSON or printable HTML"
                    }
                  }
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/payments/{id}/receipt": {
      "get": {
        "tags": [
          "payments"
        ],
        "summary": "رسید payment",
        "description": "format=json by default; html is escaped and printable. Current settlement plus historical balance-at-posting; legacy documents use UUID as reference.\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "html"
              ],
              "default": "json"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Receipt JSON or printable HTML",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "Receipt JSON or printable HTML"
                    }
                  }
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/reports/trades/export": {
      "post": {
        "tags": [
          "reports"
        ],
        "summary": "خروجی CSV trades",
        "description": "Read-only; exact filters/fields/sort of report, no page/limit. Default cap 5000; maximum 10000. String formula prefixes escaped. No partial files.\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "search": {
                    "type": "string",
                    "maxLength": 150,
                    "default": ""
                  },
                  "filters": {
                    "type": "object",
                    "properties": {
                      "customerId": {
                        "type": "integer",
                        "exclusiveMinimum": true,
                        "minimum": 0,
                        "maximum": 2147483647
                      },
                      "currency": {
                        "type": "string",
                        "pattern": "^[A-Z]{3}$"
                      },
                      "from": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "to": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "customerActive": {
                        "type": "boolean"
                      },
                      "status": {
                        "type": "string",
                        "enum": [
                          "POSTED",
                          "VOID"
                        ]
                      },
                      "minAmount": {
                        "type": "string",
                        "pattern": "^-?(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                      },
                      "maxAmount": {
                        "type": "string",
                        "pattern": "^-?(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                      }
                    },
                    "additionalProperties": false,
                    "default": {}
                  },
                  "fields": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "id",
                        "documentNumber",
                        "profitStatus",
                        "customerId",
                        "customerName",
                        "customerCode",
                        "customerPhone",
                        "receivedCurrency",
                        "receivedAmount",
                        "paidCurrency",
                        "paidAmount",
                        "agreedRate",
                        "receivedEurRate",
                        "paidEurRate",
                        "feePercent",
                        "feeAmount",
                        "feeEur",
                        "costBasisEur",
                        "exchangeProfitEur",
                        "status",
                        "createdAt",
                        "notes"
                      ]
                    },
                    "minItems": 1,
                    "maxItems": 22,
                    "default": [
                      "id",
                      "documentNumber",
                      "customerName",
                      "receivedAmount",
                      "receivedCurrency",
                      "paidAmount",
                      "paidCurrency",
                      "feeEur",
                      "exchangeProfitEur",
                      "profitStatus",
                      "status",
                      "createdAt"
                    ]
                  },
                  "sort": {
                    "type": "object",
                    "properties": {
                      "field": {
                        "type": "string",
                        "enum": [
                          "id",
                          "documentNumber",
                          "profitStatus",
                          "customerId",
                          "customerName",
                          "customerCode",
                          "customerPhone",
                          "receivedCurrency",
                          "receivedAmount",
                          "paidCurrency",
                          "paidAmount",
                          "agreedRate",
                          "receivedEurRate",
                          "paidEurRate",
                          "feePercent",
                          "feeAmount",
                          "feeEur",
                          "costBasisEur",
                          "exchangeProfitEur",
                          "status",
                          "createdAt"
                        ]
                      },
                      "direction": {
                        "type": "string",
                        "enum": [
                          "asc",
                          "desc"
                        ]
                      }
                    },
                    "required": [
                      "field",
                      "direction"
                    ],
                    "additionalProperties": false,
                    "default": {
                      "field": "createdAt",
                      "direction": "desc"
                    }
                  },
                  "maxRows": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10000,
                    "default": 5000
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "filters": {},
                "maxRows": 5000
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "UTF-8 CSV with BOM, bounded to maxRows; 422 if too large",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/reports/payments/export": {
      "post": {
        "tags": [
          "reports"
        ],
        "summary": "خروجی CSV payments",
        "description": "Read-only; exact filters/fields/sort of report, no page/limit. Default cap 5000; maximum 10000. String formula prefixes escaped. No partial files.\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "search": {
                    "type": "string",
                    "maxLength": 150,
                    "default": ""
                  },
                  "filters": {
                    "type": "object",
                    "properties": {
                      "customerId": {
                        "type": "integer",
                        "exclusiveMinimum": true,
                        "minimum": 0,
                        "maximum": 2147483647
                      },
                      "currency": {
                        "type": "string",
                        "pattern": "^[A-Z]{3}$"
                      },
                      "from": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "to": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "customerActive": {
                        "type": "boolean"
                      },
                      "status": {
                        "type": "string",
                        "enum": [
                          "POSTED",
                          "VOID"
                        ]
                      },
                      "direction": {
                        "type": "string",
                        "enum": [
                          "RECEIVE",
                          "PAY"
                        ]
                      },
                      "tradeId": {
                        "type": "string",
                        "format": "uuid"
                      },
                      "minAmount": {
                        "type": "string",
                        "pattern": "^-?(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                      },
                      "maxAmount": {
                        "type": "string",
                        "pattern": "^-?(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                      }
                    },
                    "additionalProperties": false,
                    "default": {}
                  },
                  "fields": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "id",
                        "documentNumber",
                        "unallocatedAmount",
                        "customerId",
                        "customerName",
                        "customerCode",
                        "customerPhone",
                        "tradeId",
                        "currencyCode",
                        "direction",
                        "amount",
                        "eurRate",
                        "eurAmount",
                        "status",
                        "createdAt",
                        "notes"
                      ]
                    },
                    "minItems": 1,
                    "maxItems": 16,
                    "default": [
                      "id",
                      "documentNumber",
                      "customerName",
                      "currencyCode",
                      "direction",
                      "amount",
                      "unallocatedAmount",
                      "eurRate",
                      "status",
                      "createdAt"
                    ]
                  },
                  "sort": {
                    "type": "object",
                    "properties": {
                      "field": {
                        "type": "string",
                        "enum": [
                          "id",
                          "documentNumber",
                          "unallocatedAmount",
                          "customerId",
                          "customerName",
                          "customerCode",
                          "customerPhone",
                          "tradeId",
                          "currencyCode",
                          "direction",
                          "amount",
                          "eurRate",
                          "eurAmount",
                          "status",
                          "createdAt"
                        ]
                      },
                      "direction": {
                        "type": "string",
                        "enum": [
                          "asc",
                          "desc"
                        ]
                      }
                    },
                    "required": [
                      "field",
                      "direction"
                    ],
                    "additionalProperties": false,
                    "default": {
                      "field": "createdAt",
                      "direction": "desc"
                    }
                  },
                  "maxRows": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10000,
                    "default": 5000
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "filters": {},
                "maxRows": 5000
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "UTF-8 CSV with BOM, bounded to maxRows; 422 if too large",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/reports/statement/export": {
      "post": {
        "tags": [
          "reports"
        ],
        "summary": "خروجی CSV statement",
        "description": "Read-only; exact filters/fields/sort of report, no page/limit. Default cap 5000; maximum 10000. String formula prefixes escaped. No partial files.\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "search": {
                    "type": "string",
                    "maxLength": 150,
                    "default": ""
                  },
                  "filters": {
                    "type": "object",
                    "properties": {
                      "customerId": {
                        "type": "integer",
                        "exclusiveMinimum": true,
                        "minimum": 0,
                        "maximum": 2147483647
                      },
                      "currency": {
                        "type": "string",
                        "pattern": "^[A-Z]{3}$"
                      },
                      "from": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "to": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "customerActive": {
                        "type": "boolean"
                      },
                      "source": {
                        "type": "string",
                        "enum": [
                          "TRADE",
                          "PAYMENT",
                          "OPENING",
                          "REVERSAL"
                        ]
                      },
                      "minAmount": {
                        "type": "string",
                        "pattern": "^-?(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                      },
                      "maxAmount": {
                        "type": "string",
                        "pattern": "^-?(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                      }
                    },
                    "required": [
                      "customerId"
                    ],
                    "additionalProperties": false,
                    "default": {}
                  },
                  "fields": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "id",
                        "customerId",
                        "customerName",
                        "customerCode",
                        "customerPhone",
                        "currencyCode",
                        "amount",
                        "runningBalance",
                        "eurRate",
                        "eurAmount",
                        "source",
                        "tradeId",
                        "paymentId",
                        "openingId",
                        "reversalOf",
                        "createdAt"
                      ]
                    },
                    "minItems": 1,
                    "maxItems": 16,
                    "default": [
                      "id",
                      "customerName",
                      "currencyCode",
                      "amount",
                      "runningBalance",
                      "source",
                      "createdAt"
                    ]
                  },
                  "sort": {
                    "type": "object",
                    "properties": {
                      "field": {
                        "type": "string",
                        "enum": [
                          "id",
                          "customerId",
                          "customerName",
                          "customerCode",
                          "customerPhone",
                          "currencyCode",
                          "amount",
                          "runningBalance",
                          "eurRate",
                          "eurAmount",
                          "source",
                          "tradeId",
                          "paymentId",
                          "openingId",
                          "reversalOf",
                          "createdAt"
                        ]
                      },
                      "direction": {
                        "type": "string",
                        "enum": [
                          "asc",
                          "desc"
                        ]
                      }
                    },
                    "required": [
                      "field",
                      "direction"
                    ],
                    "additionalProperties": false,
                    "default": {
                      "field": "createdAt",
                      "direction": "asc"
                    }
                  },
                  "maxRows": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10000,
                    "default": 5000
                  }
                },
                "required": [
                  "filters"
                ],
                "additionalProperties": false
              },
              "example": {
                "filters": {
                  "customerId": 1
                },
                "maxRows": 5000
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "UTF-8 CSV with BOM, bounded to maxRows; 422 if too large",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/reports/balances/export": {
      "post": {
        "tags": [
          "reports"
        ],
        "summary": "خروجی CSV balances",
        "description": "Read-only; exact filters/fields/sort of report, no page/limit. Default cap 5000; maximum 10000. String formula prefixes escaped. No partial files.\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "search": {
                    "type": "string",
                    "maxLength": 150,
                    "default": ""
                  },
                  "filters": {
                    "type": "object",
                    "properties": {
                      "customerId": {
                        "type": "integer",
                        "exclusiveMinimum": true,
                        "minimum": 0,
                        "maximum": 2147483647
                      },
                      "currency": {
                        "type": "string",
                        "pattern": "^[A-Z]{3}$"
                      },
                      "customerActive": {
                        "type": "boolean"
                      },
                      "asOf": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "side": {
                        "type": "string",
                        "enum": [
                          "CUSTOMER_OWES",
                          "CUSTOMER_IS_OWED",
                          "SETTLED"
                        ]
                      },
                      "minAmount": {
                        "type": "string",
                        "pattern": "^-?(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                      },
                      "maxAmount": {
                        "type": "string",
                        "pattern": "^-?(0|[1-9]\\d{0,15})(\\.\\d{1,8})?$"
                      }
                    },
                    "additionalProperties": false,
                    "default": {}
                  },
                  "fields": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "customerId",
                        "customerName",
                        "customerCode",
                        "customerPhone",
                        "currencyCode",
                        "amount",
                        "side",
                        "eurEquivalent",
                        "eurRate",
                        "rateStatus",
                        "rateUpdatedAt"
                      ]
                    },
                    "minItems": 1,
                    "maxItems": 11,
                    "default": [
                      "customerId",
                      "customerName",
                      "currencyCode",
                      "amount",
                      "side",
                      "eurEquivalent",
                      "rateStatus",
                      "rateUpdatedAt"
                    ]
                  },
                  "sort": {
                    "type": "object",
                    "properties": {
                      "field": {
                        "type": "string",
                        "enum": [
                          "customerId",
                          "customerName",
                          "customerCode",
                          "customerPhone",
                          "currencyCode",
                          "amount",
                          "side",
                          "eurEquivalent",
                          "eurRate",
                          "rateStatus",
                          "rateUpdatedAt"
                        ]
                      },
                      "direction": {
                        "type": "string",
                        "enum": [
                          "asc",
                          "desc"
                        ]
                      }
                    },
                    "required": [
                      "field",
                      "direction"
                    ],
                    "additionalProperties": false,
                    "default": {
                      "field": "customerId",
                      "direction": "asc"
                    }
                  },
                  "maxRows": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10000,
                    "default": 5000
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "filters": {},
                "maxRows": 5000
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "UTF-8 CSV with BOM, bounded to maxRows; 422 if too large",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/reports/customer-profit/export": {
      "post": {
        "tags": [
          "reports"
        ],
        "summary": "خروجی CSV customer-profit",
        "description": "Read-only; exact filters/fields/sort of report, no page/limit. Default cap 5000; maximum 10000. String formula prefixes escaped. No partial files.\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "search": {
                    "type": "string",
                    "maxLength": 150,
                    "default": ""
                  },
                  "filters": {
                    "type": "object",
                    "properties": {
                      "customerId": {
                        "type": "integer",
                        "exclusiveMinimum": true,
                        "minimum": 0,
                        "maximum": 2147483647
                      },
                      "currency": {
                        "type": "string",
                        "pattern": "^[A-Z]{3}$"
                      },
                      "from": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "to": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "customerActive": {
                        "type": "boolean"
                      }
                    },
                    "additionalProperties": false,
                    "default": {}
                  },
                  "fields": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "customerId",
                        "customerName",
                        "customerCode",
                        "customerPhone",
                        "tradeCount",
                        "feeRevenueEur",
                        "knownExchangeProfitEur",
                        "knownSubtotalEur",
                        "unknownProfitTrades",
                        "totalProfitEur"
                      ]
                    },
                    "minItems": 1,
                    "maxItems": 10,
                    "default": [
                      "customerId",
                      "customerName",
                      "tradeCount",
                      "feeRevenueEur",
                      "knownExchangeProfitEur",
                      "unknownProfitTrades",
                      "totalProfitEur"
                    ]
                  },
                  "sort": {
                    "type": "object",
                    "properties": {
                      "field": {
                        "type": "string",
                        "enum": [
                          "customerId",
                          "customerName",
                          "customerCode",
                          "customerPhone",
                          "tradeCount",
                          "feeRevenueEur",
                          "knownExchangeProfitEur",
                          "knownSubtotalEur",
                          "unknownProfitTrades",
                          "totalProfitEur"
                        ]
                      },
                      "direction": {
                        "type": "string",
                        "enum": [
                          "asc",
                          "desc"
                        ]
                      }
                    },
                    "required": [
                      "field",
                      "direction"
                    ],
                    "additionalProperties": false,
                    "default": {
                      "field": "feeRevenueEur",
                      "direction": "desc"
                    }
                  },
                  "maxRows": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10000,
                    "default": 5000
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "filters": {},
                "maxRows": 5000
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "UTF-8 CSV with BOM, bounded to maxRows; 422 if too large",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/report-presets": {
      "get": {
        "tags": [
          "report-presets"
        ],
        "summary": "تنظیمات گزارش شخصی",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 1000,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 80
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ items, total, page, limit }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "{ items, total, page, limit }"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "report-presets"
        ],
        "summary": "ذخیره تنظیم گزارش",
        "description": "Private to current user. Config is validated with the report schema; page is reset to 1.\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 80
                  },
                  "report": {
                    "type": "string",
                    "enum": [
                      "trades",
                      "payments",
                      "statement",
                      "balances",
                      "customer-profit"
                    ]
                  },
                  "config": {
                    "type": "object",
                    "additionalProperties": {}
                  }
                },
                "required": [
                  "name",
                  "report",
                  "config"
                ],
                "additionalProperties": false
              },
              "example": {
                "name": "معاملات دلار",
                "report": "trades",
                "config": {
                  "filters": {
                    "currency": "USD"
                  },
                  "limit": 25
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "ReportPreset",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ReportPreset"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/report-presets/{id}": {
      "get": {
        "tags": [
          "report-presets"
        ],
        "summary": "جزئیات تنظیم شخصی",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ReportPreset",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ReportPreset"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "report-presets"
        ],
        "summary": "ویرایش تنظیم شخصی با کنترل نسخه",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "expectedVersion": {
                    "type": "integer",
                    "exclusiveMinimum": true,
                    "minimum": 0,
                    "maximum": 2147483647
                  },
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 80
                  },
                  "config": {
                    "type": "object",
                    "additionalProperties": {}
                  }
                },
                "required": [
                  "expectedVersion"
                ],
                "additionalProperties": false
              },
              "example": {
                "expectedVersion": 1,
                "name": "گزارش معاملات روزانه"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "ReportPreset",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ReportPreset"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "report-presets"
        ],
        "summary": "حذف تنظیم شخصی",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "expectedVersion",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 2147483647
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ deleted: true }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "{ deleted: true }"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/report-presets/{id}/run": {
      "post": {
        "tags": [
          "report-presets"
        ],
        "summary": "اجرای تنظیم ذخیره‌شده",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10000
                  },
                  "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 100
                  }
                },
                "additionalProperties": false
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "ReportEnvelope",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta",
                    "summary",
                    "columns"
                  ],
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/trade-text/template": {
      "get": {
        "tags": [
          "trade-text"
        ],
        "summary": "قالب ثبت متنی معامله",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "{ version, template, required, optional }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "{ version, template, required, optional }"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/trade-text/preview": {
      "post": {
        "tags": [
          "trade-text"
        ],
        "summary": "بررسی و پیش‌نمایش متن معامله",
        "description": "No ledger posting. Customer code is required. Amounts are obligations, not cash movements. Preview is informational; creation recalculates current defaults.\n\nRoles: ADMIN, CASHIER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 5000
                  }
                },
                "required": [
                  "text"
                ],
                "additionalProperties": false
              },
              "example": {
                "text": "مشتری: C001\nدریافتی: 1000 USD\nپرداختی: 910 EUR\nکارمزد: 0.5\nنرخ یورویی دریافتی: 0.92\nهزینه یورویی: 910\nتوضیحات: معامله نمونه"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Pricing and warnings",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "Pricing and warnings"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/trade-text": {
      "post": {
        "tags": [
          "trade-text"
        ],
        "summary": "ثبت معامله از متن قالب‌دار",
        "description": "Same atomic accounting service as POST /api/trades. Required customer code; received principal excludes fee. Paid amount must match supported rate and currency precision. Does not create Payment. Reuse the same Idempotency-Key on retry.\n\nRoles: ADMIN, CASHIER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 100
            },
            "example": "example-key-0001"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 5000
                  }
                },
                "required": [
                  "text"
                ],
                "additionalProperties": false
              },
              "example": {
                "text": "مشتری: C001\nدریافتی: 1000 USD\nپرداختی: 910 EUR\nکارمزد: 0.5\nنرخ یورویی دریافتی: 0.92\nهزینه یورویی: 910\nتوضیحات: معامله نمونه"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "trade",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Trade"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/text-imports/templates": {
      "get": {
        "tags": [
          "text-imports"
        ],
        "summary": "قالب‌های کامل عملیات متنی",
        "description": "\n\nRoles: ADMIN, CASHIER, VIEWER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Templates, limits, field descriptions and operation rules",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "Templates, limits, field descriptions and operation rules"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/text-imports/parse": {
      "post": {
        "tags": [
          "text-imports"
        ],
        "summary": "تجزیه متن بدون مراجعه به دیتابیس کسب‌وکار",
        "description": "Authentication still queries the session. Syntax only; does not resolve customers, prices or post anything. Invalid syntax returns 200 valid=false.\n\nRoles: ADMIN, CASHIER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 15000
                  }
                },
                "required": [
                  "text"
                ],
                "additionalProperties": false
              },
              "example": {
                "text": "مشتری: C001\nدریافتی: 1000 USD\nپرداختی: 910 EUR\nکارمزد: 0.5\nنرخ یورویی دریافتی: 0.92"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ valid, records, errors }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "{ valid, records, errors }"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/text-imports/validate": {
      "post": {
        "tags": [
          "text-imports"
        ],
        "summary": "اعتبارسنجی همه رکوردها و محاسبه اثر مالی",
        "description": "Read-only; checks customers, currencies, rates, references and precision. Does not save a preview or financial data. Invalid records return 200 valid=false.\n\nRoles: ADMIN, CASHIER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 15000
                  }
                },
                "required": [
                  "text"
                ],
                "additionalProperties": false
              },
              "example": {
                "text": "مشتری: C001\nدریافتی: 1000 USD\nپرداختی: 910 EUR\nکارمزد: 0.5\nنرخ یورویی دریافتی: 0.92\n---\nنوع: دریافت\nمشتری: C001\nمبلغ: 100 USD\nنرخ یورویی: 0.92\nتخصیص: AUTO"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ valid, records, errors, summary? }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "formatVersion": {
                          "type": "integer",
                          "enum": [
                            2
                          ]
                        },
                        "valid": {
                          "type": "boolean"
                        },
                        "records": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "index": {
                                "type": "integer"
                              },
                              "kind": {
                                "type": "string",
                                "enum": [
                                  "TRADE",
                                  "RECEIVE",
                                  "PAY"
                                ]
                              },
                              "customer": {
                                "type": "object",
                                "properties": {
                                  "id": {
                                    "type": "integer"
                                  },
                                  "code": {
                                    "type": "string"
                                  },
                                  "name": {
                                    "type": "string"
                                  }
                                },
                                "required": [
                                  "id",
                                  "code",
                                  "name"
                                ]
                              },
                              "input": {
                                "type": "object",
                                "additionalProperties": true
                              },
                              "pricing": {
                                "type": "object",
                                "description": "Trade prices; exact decimal strings",
                                "additionalProperties": {
                                  "type": "string",
                                  "nullable": true
                                }
                              },
                              "settlement": {
                                "type": "string",
                                "enum": [
                                  "NONE",
                                  "FULL",
                                  "PARTIAL"
                                ]
                              },
                              "payments": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "customerId": {
                                      "type": "integer"
                                    },
                                    "tradeId": {
                                      "type": "string",
                                      "format": "uuid"
                                    },
                                    "currencyCode": {
                                      "type": "string"
                                    },
                                    "direction": {
                                      "type": "string",
                                      "enum": [
                                        "RECEIVE",
                                        "PAY"
                                      ]
                                    },
                                    "amount": {
                                      "type": "string",
                                      "description": "Exact decimal string; do not convert to JS Number"
                                    },
                                    "eurRate": {
                                      "type": "string",
                                      "description": "Exact decimal string; do not convert to JS Number"
                                    },
                                    "allocationMode": {
                                      "type": "string",
                                      "enum": [
                                        "AUTO",
                                        "NONE"
                                      ]
                                    },
                                    "notes": {
                                      "type": "string"
                                    }
                                  },
                                  "required": [
                                    "customerId",
                                    "currencyCode",
                                    "direction",
                                    "amount",
                                    "allocationMode"
                                  ]
                                }
                              },
                              "warnings": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "code": {
                                      "type": "string"
                                    },
                                    "message": {
                                      "type": "string"
                                    }
                                  },
                                  "required": [
                                    "code",
                                    "message"
                                  ]
                                }
                              },
                              "recordAlias": {
                                "type": "string"
                              },
                              "externalReference": {
                                "type": "string"
                              },
                              "localTradeIndex": {
                                "type": "integer"
                              }
                            },
                            "required": [
                              "index",
                              "kind",
                              "customer",
                              "input",
                              "payments",
                              "warnings"
                            ]
                          }
                        },
                        "errors": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "record": {
                                "type": "integer"
                              },
                              "line": {
                                "type": "integer"
                              },
                              "field": {
                                "type": "string"
                              },
                              "code": {
                                "type": "string"
                              },
                              "message": {
                                "type": "string"
                              },
                              "hint": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "code",
                              "message"
                            ]
                          }
                        },
                        "summary": {
                          "type": "object",
                          "properties": {
                            "recordCount": {
                              "type": "integer"
                            },
                            "tradeCount": {
                              "type": "integer"
                            },
                            "paymentCount": {
                              "type": "integer"
                            },
                            "effects": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "customerId": {
                                    "type": "integer"
                                  },
                                  "customerCode": {
                                    "type": "string"
                                  },
                                  "currency": {
                                    "type": "string"
                                  },
                                  "accountChange": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  },
                                  "cashChange": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  }
                                },
                                "required": [
                                  "customerId",
                                  "currency",
                                  "accountChange",
                                  "cashChange"
                                ]
                              }
                            },
                            "balances": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "customerId": {
                                    "type": "integer"
                                  },
                                  "customerCode": {
                                    "type": "string"
                                  },
                                  "currency": {
                                    "type": "string"
                                  },
                                  "before": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  },
                                  "after": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  },
                                  "accountChange": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  },
                                  "cashChange": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  }
                                },
                                "required": [
                                  "customerId",
                                  "currency",
                                  "before",
                                  "after",
                                  "accountChange"
                                ]
                              }
                            }
                          },
                          "required": [
                            "recordCount",
                            "tradeCount",
                            "paymentCount",
                            "effects"
                          ]
                        }
                      },
                      "required": [
                        "formatVersion",
                        "valid",
                        "records",
                        "errors"
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/text-imports/preview": {
      "post": {
        "tags": [
          "text-imports"
        ],
        "summary": "پیش‌نمایش قابل تأیید با اعتبار پنج دقیقه",
        "description": "Stores a user-bound preview but no ledger entry. Pass previewId and the same text to commit. All validation errors are returned in error.details.errors.\n\nRoles: ADMIN, CASHIER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 15000
                  }
                },
                "required": [
                  "text"
                ],
                "additionalProperties": false
              },
              "example": {
                "text": "نوع: معامله\nمشتری: C001\nدریافتی: ۱٬۰۰۰ USD\nپرداختی: ۹۱۰ EUR\nکارمزد: ۰٫۵\nنرخ یورویی دریافتی: ۰٫۹۲\nتسویه: کامل"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ valid, records, summary, previewId, expiresAt }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "formatVersion": {
                          "type": "integer",
                          "enum": [
                            2
                          ]
                        },
                        "valid": {
                          "type": "boolean"
                        },
                        "records": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "index": {
                                "type": "integer"
                              },
                              "kind": {
                                "type": "string",
                                "enum": [
                                  "TRADE",
                                  "RECEIVE",
                                  "PAY"
                                ]
                              },
                              "customer": {
                                "type": "object",
                                "properties": {
                                  "id": {
                                    "type": "integer"
                                  },
                                  "code": {
                                    "type": "string"
                                  },
                                  "name": {
                                    "type": "string"
                                  }
                                },
                                "required": [
                                  "id",
                                  "code",
                                  "name"
                                ]
                              },
                              "input": {
                                "type": "object",
                                "additionalProperties": true
                              },
                              "pricing": {
                                "type": "object",
                                "description": "Trade prices; exact decimal strings",
                                "additionalProperties": {
                                  "type": "string",
                                  "nullable": true
                                }
                              },
                              "settlement": {
                                "type": "string",
                                "enum": [
                                  "NONE",
                                  "FULL",
                                  "PARTIAL"
                                ]
                              },
                              "payments": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "customerId": {
                                      "type": "integer"
                                    },
                                    "tradeId": {
                                      "type": "string",
                                      "format": "uuid"
                                    },
                                    "currencyCode": {
                                      "type": "string"
                                    },
                                    "direction": {
                                      "type": "string",
                                      "enum": [
                                        "RECEIVE",
                                        "PAY"
                                      ]
                                    },
                                    "amount": {
                                      "type": "string",
                                      "description": "Exact decimal string; do not convert to JS Number"
                                    },
                                    "eurRate": {
                                      "type": "string",
                                      "description": "Exact decimal string; do not convert to JS Number"
                                    },
                                    "allocationMode": {
                                      "type": "string",
                                      "enum": [
                                        "AUTO",
                                        "NONE"
                                      ]
                                    },
                                    "notes": {
                                      "type": "string"
                                    }
                                  },
                                  "required": [
                                    "customerId",
                                    "currencyCode",
                                    "direction",
                                    "amount",
                                    "allocationMode"
                                  ]
                                }
                              },
                              "warnings": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "code": {
                                      "type": "string"
                                    },
                                    "message": {
                                      "type": "string"
                                    }
                                  },
                                  "required": [
                                    "code",
                                    "message"
                                  ]
                                }
                              },
                              "recordAlias": {
                                "type": "string"
                              },
                              "externalReference": {
                                "type": "string"
                              },
                              "localTradeIndex": {
                                "type": "integer"
                              }
                            },
                            "required": [
                              "index",
                              "kind",
                              "customer",
                              "input",
                              "payments",
                              "warnings"
                            ]
                          }
                        },
                        "errors": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "record": {
                                "type": "integer"
                              },
                              "line": {
                                "type": "integer"
                              },
                              "field": {
                                "type": "string"
                              },
                              "code": {
                                "type": "string"
                              },
                              "message": {
                                "type": "string"
                              },
                              "hint": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "code",
                              "message"
                            ]
                          }
                        },
                        "summary": {
                          "type": "object",
                          "properties": {
                            "recordCount": {
                              "type": "integer"
                            },
                            "tradeCount": {
                              "type": "integer"
                            },
                            "paymentCount": {
                              "type": "integer"
                            },
                            "effects": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "customerId": {
                                    "type": "integer"
                                  },
                                  "customerCode": {
                                    "type": "string"
                                  },
                                  "currency": {
                                    "type": "string"
                                  },
                                  "accountChange": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  },
                                  "cashChange": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  }
                                },
                                "required": [
                                  "customerId",
                                  "currency",
                                  "accountChange",
                                  "cashChange"
                                ]
                              }
                            },
                            "balances": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "customerId": {
                                    "type": "integer"
                                  },
                                  "customerCode": {
                                    "type": "string"
                                  },
                                  "currency": {
                                    "type": "string"
                                  },
                                  "before": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  },
                                  "after": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  },
                                  "accountChange": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  },
                                  "cashChange": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  }
                                },
                                "required": [
                                  "customerId",
                                  "currency",
                                  "before",
                                  "after",
                                  "accountChange"
                                ]
                              }
                            }
                          },
                          "required": [
                            "recordCount",
                            "tradeCount",
                            "paymentCount",
                            "effects"
                          ]
                        },
                        "previewId": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "expiresAt": {
                          "type": "string",
                          "format": "date-time"
                        }
                      },
                      "required": [
                        "formatVersion",
                        "valid",
                        "records",
                        "errors",
                        "previewId",
                        "expiresAt",
                        "summary"
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/text-imports": {
      "post": {
        "tags": [
          "text-imports"
        ],
        "summary": "ثبت اتمیک متن تکی یا گروهی",
        "description": "Up to 20 records. All-or-nothing. Preview is optional; supplied preview binds input and calculated prices. FULL settlement explicitly creates real RECEIVE and PAY. Idempotency-Key belongs to the whole batch. Never retry an uncertain request with a new key.\n\nRoles: ADMIN, CASHIER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 100
            },
            "example": "example-key-0001"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 15000
                  },
                  "previewId": {
                    "type": "string",
                    "format": "uuid"
                  }
                },
                "required": [
                  "text"
                ],
                "additionalProperties": false
              },
              "example": {
                "text": "مشتری: C001\nدریافتی: 1000 USD\nپرداختی: 910 EUR\nکارمزد: 0.5\nنرخ یورویی دریافتی: 0.92"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "{ importId, formatVersion, replayed, summary, documents }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "importId": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "formatVersion": {
                          "type": "integer",
                          "enum": [
                            2
                          ]
                        },
                        "createdAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "replayed": {
                          "type": "boolean"
                        },
                        "summary": {
                          "type": "object",
                          "properties": {
                            "recordCount": {
                              "type": "integer"
                            },
                            "tradeCount": {
                              "type": "integer"
                            },
                            "paymentCount": {
                              "type": "integer"
                            },
                            "effects": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "customerId": {
                                    "type": "integer"
                                  },
                                  "customerCode": {
                                    "type": "string"
                                  },
                                  "currency": {
                                    "type": "string"
                                  },
                                  "accountChange": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  },
                                  "cashChange": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  }
                                },
                                "required": [
                                  "customerId",
                                  "currency",
                                  "accountChange",
                                  "cashChange"
                                ]
                              }
                            },
                            "balances": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "customerId": {
                                    "type": "integer"
                                  },
                                  "customerCode": {
                                    "type": "string"
                                  },
                                  "currency": {
                                    "type": "string"
                                  },
                                  "before": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  },
                                  "after": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  },
                                  "accountChange": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  },
                                  "cashChange": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  }
                                },
                                "required": [
                                  "customerId",
                                  "currency",
                                  "before",
                                  "after",
                                  "accountChange"
                                ]
                              }
                            }
                          },
                          "required": [
                            "recordCount",
                            "tradeCount",
                            "paymentCount",
                            "effects"
                          ]
                        },
                        "documents": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "record": {
                                "type": "integer"
                              },
                              "kind": {
                                "type": "string"
                              },
                              "customer": {
                                "type": "object",
                                "properties": {
                                  "id": {
                                    "type": "integer"
                                  },
                                  "code": {
                                    "type": "string"
                                  },
                                  "name": {
                                    "type": "string"
                                  }
                                },
                                "required": [
                                  "id",
                                  "code",
                                  "name"
                                ]
                              },
                              "trade": {
                                "$ref": "#/components/schemas/Trade"
                              },
                              "payments": {
                                "type": "array",
                                "items": {
                                  "$ref": "#/components/schemas/Payment"
                                }
                              },
                              "warnings": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "code": {
                                      "type": "string"
                                    },
                                    "message": {
                                      "type": "string"
                                    }
                                  },
                                  "required": [
                                    "code",
                                    "message"
                                  ]
                                }
                              },
                              "recordAlias": {
                                "type": "string"
                              },
                              "externalReference": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "record",
                              "kind",
                              "customer",
                              "payments",
                              "warnings"
                            ]
                          }
                        }
                      },
                      "required": [
                        "importId",
                        "formatVersion",
                        "createdAt",
                        "replayed",
                        "summary",
                        "documents"
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "text-imports"
        ],
        "summary": "تاریخچه ثبت‌های متنی خود کاربر",
        "description": "Optional reference filter matches an exact external reference, normalized to uppercase; owner only.\n\nRoles: ADMIN, CASHIER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 1000,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "reference",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ items, total, page, limit }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "{ items, total, page, limit }"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/text-imports/{id}": {
      "get": {
        "tags": [
          "text-imports"
        ],
        "summary": "متن اصلی و نتیجه ثبت همراه وضعیت جاری اسناد",
        "description": "Owner only, including admins. Stored result is historical; currentDocuments contains current POSTED/VOID states. Reverse individual documents through existing void APIs.\n\nRoles: ADMIN, CASHIER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ id, sourceText, result, currentDocuments, createdAt }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "{ id, sourceText, result, currentDocuments, createdAt }"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/text-drafts": {
      "post": {
        "tags": [
          "text-drafts"
        ],
        "summary": "ذخیره پیش‌نویس متنی بدون ثبت مالی",
        "description": "Text may be incomplete or empty. Owner only. No financial posting; validate on preview.\n\nRoles: ADMIN, CASHIER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 120,
                    "default": "پیش‌نویس جدید"
                  },
                  "text": {
                    "type": "string",
                    "maxLength": 15000,
                    "default": ""
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "title": "معاملات امروز",
                "text": "مشتری: C001\nدریافتی: 1000 USD\nپرداختی: 910 EUR\nکارمزد: 0.5\nنرخ یورویی دریافتی: 0.92"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "TextDraftView",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "title": {
                          "type": "string"
                        },
                        "text": {
                          "type": "string"
                        },
                        "version": {
                          "type": "integer"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "DRAFT",
                            "COMMITTED"
                          ]
                        },
                        "importId": {
                          "type": "string",
                          "nullable": true,
                          "format": "uuid"
                        },
                        "createdAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "updatedAt": {
                          "type": "string",
                          "format": "date-time"
                        }
                      },
                      "required": [
                        "id",
                        "title",
                        "version",
                        "status"
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "text-drafts"
        ],
        "summary": "فهرست پیش‌نویس‌های شخصی",
        "description": "Search title; filter status; text excluded from list. GET details to edit.\n\nRoles: ADMIN, CASHIER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 1000,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "DRAFT",
                "COMMITTED"
              ]
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 120
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ items, total, page, limit }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "{ items, total, page, limit }"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/text-drafts/{id}": {
      "get": {
        "tags": [
          "text-drafts"
        ],
        "summary": "خواندن متن و نسخه پیش‌نویس",
        "description": "\n\nRoles: ADMIN, CASHIER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "TextDraftView",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "title": {
                          "type": "string"
                        },
                        "text": {
                          "type": "string"
                        },
                        "version": {
                          "type": "integer"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "DRAFT",
                            "COMMITTED"
                          ]
                        },
                        "importId": {
                          "type": "string",
                          "nullable": true,
                          "format": "uuid"
                        },
                        "createdAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "updatedAt": {
                          "type": "string",
                          "format": "date-time"
                        }
                      },
                      "required": [
                        "id",
                        "title",
                        "version",
                        "status"
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "text-drafts"
        ],
        "summary": "ویرایش پیش‌نویس با کنترل نسخه",
        "description": "No overwriting concurrent edits. Returns VERSION_CONFLICT for stale version; committed drafts are immutable.\n\nRoles: ADMIN, CASHIER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "expectedVersion": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 2147483647
                  },
                  "title": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 120
                  },
                  "text": {
                    "type": "string",
                    "maxLength": 15000
                  }
                },
                "required": [
                  "expectedVersion"
                ],
                "additionalProperties": false
              },
              "example": {
                "expectedVersion": 1,
                "text": "نوع: معامله\nمشتری: C001\nدریافتی: 1000 USD\nپرداختی: 910 EUR\nنرخ یورویی دریافتی: 0.92\nتسویه: جزئی\nدریافت واقعی: 500 USD\nپرداخت واقعی: 200 EUR"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "TextDraftView",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "title": {
                          "type": "string"
                        },
                        "text": {
                          "type": "string"
                        },
                        "version": {
                          "type": "integer"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "DRAFT",
                            "COMMITTED"
                          ]
                        },
                        "importId": {
                          "type": "string",
                          "nullable": true,
                          "format": "uuid"
                        },
                        "createdAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "updatedAt": {
                          "type": "string",
                          "format": "date-time"
                        }
                      },
                      "required": [
                        "id",
                        "title",
                        "version",
                        "status"
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "text-drafts"
        ],
        "summary": "حذف پیش‌نویس ثبت‌نشده",
        "description": "Committed drafts cannot be deleted. No financial document is removed.\n\nRoles: ADMIN, CASHIER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "expectedVersion",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "exclusiveMinimum": true,
              "minimum": 0,
              "maximum": 2147483647
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ deleted: true }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "description": "{ deleted: true }"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/text-drafts/{id}/preview": {
      "post": {
        "tags": [
          "text-drafts"
        ],
        "summary": "بررسی پیش‌نویس و ساخت پیش‌نمایش",
        "description": "No financial posting. Input/rates/balances bind the returned preview; version must still match on commit.\n\nRoles: ADMIN, CASHIER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "expectedVersion": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 2147483647
                  }
                },
                "required": [
                  "expectedVersion"
                ],
                "additionalProperties": false
              },
              "example": {
                "expectedVersion": 1
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Preview with draft.id and draft.version",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "formatVersion": {
                          "type": "integer",
                          "enum": [
                            2
                          ]
                        },
                        "valid": {
                          "type": "boolean"
                        },
                        "records": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "index": {
                                "type": "integer"
                              },
                              "kind": {
                                "type": "string",
                                "enum": [
                                  "TRADE",
                                  "RECEIVE",
                                  "PAY"
                                ]
                              },
                              "customer": {
                                "type": "object",
                                "properties": {
                                  "id": {
                                    "type": "integer"
                                  },
                                  "code": {
                                    "type": "string"
                                  },
                                  "name": {
                                    "type": "string"
                                  }
                                },
                                "required": [
                                  "id",
                                  "code",
                                  "name"
                                ]
                              },
                              "input": {
                                "type": "object",
                                "additionalProperties": true
                              },
                              "pricing": {
                                "type": "object",
                                "description": "Trade prices; exact decimal strings",
                                "additionalProperties": {
                                  "type": "string",
                                  "nullable": true
                                }
                              },
                              "settlement": {
                                "type": "string",
                                "enum": [
                                  "NONE",
                                  "FULL",
                                  "PARTIAL"
                                ]
                              },
                              "payments": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "customerId": {
                                      "type": "integer"
                                    },
                                    "tradeId": {
                                      "type": "string",
                                      "format": "uuid"
                                    },
                                    "currencyCode": {
                                      "type": "string"
                                    },
                                    "direction": {
                                      "type": "string",
                                      "enum": [
                                        "RECEIVE",
                                        "PAY"
                                      ]
                                    },
                                    "amount": {
                                      "type": "string",
                                      "description": "Exact decimal string; do not convert to JS Number"
                                    },
                                    "eurRate": {
                                      "type": "string",
                                      "description": "Exact decimal string; do not convert to JS Number"
                                    },
                                    "allocationMode": {
                                      "type": "string",
                                      "enum": [
                                        "AUTO",
                                        "NONE"
                                      ]
                                    },
                                    "notes": {
                                      "type": "string"
                                    }
                                  },
                                  "required": [
                                    "customerId",
                                    "currencyCode",
                                    "direction",
                                    "amount",
                                    "allocationMode"
                                  ]
                                }
                              },
                              "warnings": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "code": {
                                      "type": "string"
                                    },
                                    "message": {
                                      "type": "string"
                                    }
                                  },
                                  "required": [
                                    "code",
                                    "message"
                                  ]
                                }
                              },
                              "recordAlias": {
                                "type": "string"
                              },
                              "externalReference": {
                                "type": "string"
                              },
                              "localTradeIndex": {
                                "type": "integer"
                              }
                            },
                            "required": [
                              "index",
                              "kind",
                              "customer",
                              "input",
                              "payments",
                              "warnings"
                            ]
                          }
                        },
                        "errors": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "record": {
                                "type": "integer"
                              },
                              "line": {
                                "type": "integer"
                              },
                              "field": {
                                "type": "string"
                              },
                              "code": {
                                "type": "string"
                              },
                              "message": {
                                "type": "string"
                              },
                              "hint": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "code",
                              "message"
                            ]
                          }
                        },
                        "summary": {
                          "type": "object",
                          "properties": {
                            "recordCount": {
                              "type": "integer"
                            },
                            "tradeCount": {
                              "type": "integer"
                            },
                            "paymentCount": {
                              "type": "integer"
                            },
                            "effects": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "customerId": {
                                    "type": "integer"
                                  },
                                  "customerCode": {
                                    "type": "string"
                                  },
                                  "currency": {
                                    "type": "string"
                                  },
                                  "accountChange": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  },
                                  "cashChange": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  }
                                },
                                "required": [
                                  "customerId",
                                  "currency",
                                  "accountChange",
                                  "cashChange"
                                ]
                              }
                            },
                            "balances": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "customerId": {
                                    "type": "integer"
                                  },
                                  "customerCode": {
                                    "type": "string"
                                  },
                                  "currency": {
                                    "type": "string"
                                  },
                                  "before": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  },
                                  "after": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  },
                                  "accountChange": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  },
                                  "cashChange": {
                                    "type": "string",
                                    "description": "Exact decimal string; do not convert to JS Number"
                                  }
                                },
                                "required": [
                                  "customerId",
                                  "currency",
                                  "before",
                                  "after",
                                  "accountChange"
                                ]
                              }
                            }
                          },
                          "required": [
                            "recordCount",
                            "tradeCount",
                            "paymentCount",
                            "effects"
                          ]
                        },
                        "previewId": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "expiresAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "draft": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "version": {
                              "type": "integer"
                            }
                          }
                        }
                      },
                      "required": [
                        "formatVersion",
                        "valid",
                        "records",
                        "errors",
                        "previewId",
                        "expiresAt",
                        "summary"
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/text-drafts/{id}/commit": {
      "post": {
        "tags": [
          "text-drafts"
        ],
        "summary": "تأیید نهایی پیش‌نویس",
        "description": "Requires the successful preview and Idempotency-Key. Draft and financial documents commit in one transaction. Retry with the SAME key and original expectedVersion; a committed draft cannot post again with a new key.\n\nRoles: ADMIN, CASHIER",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 100
            },
            "example": "example-key-0001"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "expectedVersion": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 2147483647
                  },
                  "previewId": {
                    "type": "string",
                    "format": "uuid"
                  }
                },
                "required": [
                  "expectedVersion",
                  "previewId"
                ],
                "additionalProperties": false
              },
              "example": {
                "expectedVersion": 1,
                "previewId": "00000000-0000-4000-8000-000000000001"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "{ draft: TextDraftView, result: ImportResult }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "draft": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string",
                              "format": "uuid"
                            },
                            "title": {
                              "type": "string"
                            },
                            "text": {
                              "type": "string"
                            },
                            "version": {
                              "type": "integer"
                            },
                            "status": {
                              "type": "string",
                              "enum": [
                                "DRAFT",
                                "COMMITTED"
                              ]
                            },
                            "importId": {
                              "type": "string",
                              "nullable": true,
                              "format": "uuid"
                            },
                            "createdAt": {
                              "type": "string",
                              "format": "date-time"
                            },
                            "updatedAt": {
                              "type": "string",
                              "format": "date-time"
                            }
                          },
                          "required": [
                            "id",
                            "title",
                            "version",
                            "status"
                          ]
                        },
                        "result": {
                          "type": "object",
                          "properties": {
                            "importId": {
                              "type": "string",
                              "format": "uuid"
                            },
                            "formatVersion": {
                              "type": "integer",
                              "enum": [
                                2
                              ]
                            },
                            "createdAt": {
                              "type": "string",
                              "format": "date-time"
                            },
                            "replayed": {
                              "type": "boolean"
                            },
                            "summary": {
                              "type": "object",
                              "properties": {
                                "recordCount": {
                                  "type": "integer"
                                },
                                "tradeCount": {
                                  "type": "integer"
                                },
                                "paymentCount": {
                                  "type": "integer"
                                },
                                "effects": {
                                  "type": "array",
                                  "items": {
                                    "type": "object",
                                    "properties": {
                                      "customerId": {
                                        "type": "integer"
                                      },
                                      "customerCode": {
                                        "type": "string"
                                      },
                                      "currency": {
                                        "type": "string"
                                      },
                                      "accountChange": {
                                        "type": "string",
                                        "description": "Exact decimal string; do not convert to JS Number"
                                      },
                                      "cashChange": {
                                        "type": "string",
                                        "description": "Exact decimal string; do not convert to JS Number"
                                      }
                                    },
                                    "required": [
                                      "customerId",
                                      "currency",
                                      "accountChange",
                                      "cashChange"
                                    ]
                                  }
                                },
                                "balances": {
                                  "type": "array",
                                  "items": {
                                    "type": "object",
                                    "properties": {
                                      "customerId": {
                                        "type": "integer"
                                      },
                                      "customerCode": {
                                        "type": "string"
                                      },
                                      "currency": {
                                        "type": "string"
                                      },
                                      "before": {
                                        "type": "string",
                                        "description": "Exact decimal string; do not convert to JS Number"
                                      },
                                      "after": {
                                        "type": "string",
                                        "description": "Exact decimal string; do not convert to JS Number"
                                      },
                                      "accountChange": {
                                        "type": "string",
                                        "description": "Exact decimal string; do not convert to JS Number"
                                      },
                                      "cashChange": {
                                        "type": "string",
                                        "description": "Exact decimal string; do not convert to JS Number"
                                      }
                                    },
                                    "required": [
                                      "customerId",
                                      "currency",
                                      "before",
                                      "after",
                                      "accountChange"
                                    ]
                                  }
                                }
                              },
                              "required": [
                                "recordCount",
                                "tradeCount",
                                "paymentCount",
                                "effects"
                              ]
                            },
                            "documents": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "record": {
                                    "type": "integer"
                                  },
                                  "kind": {
                                    "type": "string"
                                  },
                                  "customer": {
                                    "type": "object",
                                    "properties": {
                                      "id": {
                                        "type": "integer"
                                      },
                                      "code": {
                                        "type": "string"
                                      },
                                      "name": {
                                        "type": "string"
                                      }
                                    },
                                    "required": [
                                      "id",
                                      "code",
                                      "name"
                                    ]
                                  },
                                  "trade": {
                                    "$ref": "#/components/schemas/Trade"
                                  },
                                  "payments": {
                                    "type": "array",
                                    "items": {
                                      "$ref": "#/components/schemas/Payment"
                                    }
                                  },
                                  "warnings": {
                                    "type": "array",
                                    "items": {
                                      "type": "object",
                                      "properties": {
                                        "code": {
                                          "type": "string"
                                        },
                                        "message": {
                                          "type": "string"
                                        }
                                      },
                                      "required": [
                                        "code",
                                        "message"
                                      ]
                                    }
                                  },
                                  "recordAlias": {
                                    "type": "string"
                                  },
                                  "externalReference": {
                                    "type": "string"
                                  }
                                },
                                "required": [
                                  "record",
                                  "kind",
                                  "customer",
                                  "payments",
                                  "warnings"
                                ]
                              }
                            }
                          },
                          "required": [
                            "importId",
                            "formatVersion",
                            "createdAt",
                            "replayed",
                            "summary",
                            "documents"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unprocessable or CSV cap exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Database unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Opaque session token from login; expires after 12 hours."
      }
    },
    "schemas": {
      "User": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "enum": [
              "ADMIN",
              "CASHIER",
              "VIEWER"
            ]
          },
          "active": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Session": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "userId": {
            "type": "integer"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Customer": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "code": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "phone": {
            "type": "string",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "active": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Currency": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "decimals": {
            "type": "integer"
          },
          "active": {
            "type": "boolean"
          },
          "eurRate": {
            "type": "string",
            "description": "Exact decimal, serialized as string",
            "nullable": true
          },
          "rateUpdatedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "Setting": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "defaultFeePercent": {
            "type": "string",
            "description": "Exact decimal, serialized as string"
          },
          "cashEnabled": {
            "type": "boolean"
          },
          "staleRateHours": {
            "type": "integer"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Trade": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "documentNumber": {
            "type": "string",
            "nullable": true
          },
          "resultSnapshot": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true
          },
          "idempotencyKey": {
            "type": "string"
          },
          "requestHash": {
            "type": "string"
          },
          "customerId": {
            "type": "integer"
          },
          "receivedCurrency": {
            "type": "string"
          },
          "paidCurrency": {
            "type": "string"
          },
          "receivedAmount": {
            "type": "string",
            "description": "Exact decimal, serialized as string"
          },
          "paidAmount": {
            "type": "string",
            "description": "Exact decimal, serialized as string"
          },
          "agreedRate": {
            "type": "string",
            "description": "Exact decimal, serialized as string"
          },
          "receivedEurRate": {
            "type": "string",
            "description": "Exact decimal, serialized as string"
          },
          "paidEurRate": {
            "type": "string",
            "description": "Exact decimal, serialized as string"
          },
          "feePercent": {
            "type": "string",
            "description": "Exact decimal, serialized as string"
          },
          "feeAmount": {
            "type": "string",
            "description": "Exact decimal, serialized as string"
          },
          "feeEur": {
            "type": "string",
            "description": "Exact decimal, serialized as string"
          },
          "costBasisEur": {
            "type": "string",
            "description": "Exact decimal, serialized as string",
            "nullable": true
          },
          "exchangeProfitEur": {
            "type": "string",
            "description": "Exact decimal, serialized as string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "POSTED",
              "VOID"
            ]
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "createdBy": {
            "type": "integer"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "voidedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "voidReason": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "Payment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "documentNumber": {
            "type": "string",
            "nullable": true
          },
          "resultSnapshot": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true
          },
          "allocationVersion": {
            "type": "integer"
          },
          "idempotencyKey": {
            "type": "string"
          },
          "requestHash": {
            "type": "string"
          },
          "customerId": {
            "type": "integer"
          },
          "tradeId": {
            "type": "string",
            "nullable": true
          },
          "currencyCode": {
            "type": "string"
          },
          "direction": {
            "type": "string",
            "enum": [
              "RECEIVE",
              "PAY"
            ]
          },
          "amount": {
            "type": "string",
            "description": "Exact decimal, serialized as string"
          },
          "eurRate": {
            "type": "string",
            "description": "Exact decimal, serialized as string"
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "POSTED",
              "VOID"
            ]
          },
          "createdBy": {
            "type": "integer"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "voidedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "voidReason": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "OpeningBalance": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "customerId": {
            "type": "integer"
          },
          "currencyCode": {
            "type": "string"
          },
          "amount": {
            "type": "string",
            "description": "Exact decimal, serialized as string"
          },
          "eurRate": {
            "type": "string",
            "description": "Exact decimal, serialized as string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "createdBy": {
            "type": "integer"
          }
        }
      },
      "LedgerEntry": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "customerId": {
            "type": "integer"
          },
          "currencyCode": {
            "type": "string"
          },
          "amount": {
            "type": "string",
            "description": "Exact decimal, serialized as string"
          },
          "eurRate": {
            "type": "string",
            "description": "Exact decimal, serialized as string"
          },
          "tradeId": {
            "type": "string",
            "nullable": true
          },
          "paymentId": {
            "type": "string",
            "nullable": true
          },
          "openingId": {
            "type": "integer",
            "nullable": true
          },
          "reversalOf": {
            "type": "integer",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CashOpening": {
        "type": "object",
        "properties": {
          "currencyCode": {
            "type": "string"
          },
          "amount": {
            "type": "string",
            "description": "Exact decimal, serialized as string"
          },
          "createdBy": {
            "type": "integer"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AuditLog": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "actorId": {
            "type": "integer"
          },
          "action": {
            "type": "string"
          },
          "entityId": {
            "type": "string"
          },
          "detail": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "DocumentCounter": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string"
          },
          "value": {
            "type": "integer"
          }
        }
      },
      "TradePreview": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "userId": {
            "type": "integer"
          },
          "inputHash": {
            "type": "string"
          },
          "pricingHash": {
            "type": "string"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "consumedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PaymentAllocation": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "paymentId": {
            "type": "string"
          },
          "tradeId": {
            "type": "string"
          },
          "amount": {
            "type": "string",
            "description": "Exact decimal, serialized as string"
          },
          "createdBy": {
            "type": "integer"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ReportPreset": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "userId": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "report": {
            "type": "string"
          },
          "config": {
            "type": "object",
            "additionalProperties": true
          },
          "version": {
            "type": "integer"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TextImport": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "userId": {
            "type": "integer"
          },
          "idempotencyKey": {
            "type": "string"
          },
          "requestHash": {
            "type": "string"
          },
          "sourceText": {
            "type": "string"
          },
          "recordCount": {
            "type": "integer"
          },
          "result": {
            "type": "object",
            "additionalProperties": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TextImportReference": {
        "type": "object",
        "properties": {
          "reference": {
            "type": "string"
          },
          "importId": {
            "type": "string"
          },
          "recordIndex": {
            "type": "integer"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TextDraft": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "userId": {
            "type": "integer"
          },
          "title": {
            "type": "string"
          },
          "text": {
            "type": "string"
          },
          "version": {
            "type": "integer"
          },
          "importId": {
            "type": "string",
            "nullable": true
          },
          "commitKey": {
            "type": "string",
            "nullable": true
          },
          "committedVersion": {
            "type": "integer",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ProfitSummary": {
        "type": "object",
        "properties": {
          "baseCurrency": {
            "type": "string",
            "enum": [
              "EUR"
            ]
          },
          "tradeCount": {
            "type": "integer"
          },
          "unknownProfitTrades": {
            "type": "integer"
          },
          "feeRevenueEur": {
            "type": "string"
          },
          "knownExchangeProfitEur": {
            "type": "string"
          },
          "knownSubtotalEur": {
            "type": "string"
          },
          "totalProfitEur": {
            "type": "string",
            "nullable": true
          },
          "basis": {
            "type": "string"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "field": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "requestId": {
                "type": "string"
              },
              "details": {
                "type": "object"
              }
            }
          }
        }
      }
    }
  }
}