{
  "openapi": "3.0.3",
  "info": {
    "title": "ArtanClass · اتصال LMS",
    "version": "4.0.0",
    "description": "دو مرحله: ثبت کلاس با معلم و دانش‌آموزان، سپس دریافت لینک ورود با شناسهٔ شخص. ArtanClass سرویس کلاس مجازی است و ArtanLMS سامانهٔ فراخواننده. کلید روی سرور LMS نگه داشته شود."
  },
  "servers": [
    {
      "url": "https://meet.localhost",
      "description": "نصب محلی؛ در سرور آنلاین دامنهٔ واقعی جایگزین شود."
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "کلاس",
      "description": "یک کلاس دائمی برای هر کلاس LMS"
    },
    {
      "name": "ورود",
      "description": "ورود شخصی معلم و دانش‌آموز"
    }
  ],
  "paths": {
    "/api/v1/lms/classes": {
      "post": {
        "tags": [
          "کلاس"
        ],
        "summary": "۱. ثبت کلاس و اعضا",
        "description": "فقط چهار فیلد. ظرفیت خودکار از تعداد اعضا محاسبه می‌شود. درخواست تکراری کلاس جدید نمی‌سازد. برای تغییر اعضا فهرست کامل را ارسال کنید؛ تغییر هنگام جلسهٔ فعال با 409 متوقف می‌شود. نامک و محدودیت‌های استریم در پنل مدیریت می‌شوند.",
        "operationId": "upsertClass",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClassRequest"
              },
              "example": {
                "external_class_id": "math-701",
                "name": "ریاضی هفتم ۷۰۱",
                "teacher": {
                  "external_user_id": "teacher-42",
                  "name": "سمیه احمدی",
                  "national_id": "0012345679"
                },
                "students": [
                  {
                    "external_user_id": "student-101",
                    "name": "علی رضایی",
                    "national_id": "0023456787"
                  },
                  {
                    "external_user_id": "student-102",
                    "name": "مریم محمدی",
                    "national_id": "0034567895"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "کلاس موجود؛ فقط لینک ثابت",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClassResponse"
                },
                "example": {
                  "class_url": "https://meet.localhost/c/ریاضی-هفتم-۷۰۱"
                }
              }
            }
          },
          "201": {
            "description": "کلاس جدید؛ فقط لینک ثابت",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClassResponse"
                },
                "example": {
                  "class_url": "https://meet.localhost/c/ریاضی-هفتم-۷۰۱"
                }
              }
            }
          },
          "400": {
            "description": "خطای درخواست؛ متن errors برای نمایش و code برای تصمیم برنامه است.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_payload",
                  "errors": [
                    "اطلاعات درخواست را اصلاح کنید."
                  ]
                }
              }
            }
          },
          "401": {
            "description": "خطای درخواست؛ متن errors برای نمایش و code برای تصمیم برنامه است.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_payload",
                  "errors": [
                    "اطلاعات درخواست را اصلاح کنید."
                  ]
                }
              }
            }
          },
          "403": {
            "description": "خطای درخواست؛ متن errors برای نمایش و code برای تصمیم برنامه است.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_payload",
                  "errors": [
                    "اطلاعات درخواست را اصلاح کنید."
                  ]
                }
              }
            }
          },
          "404": {
            "description": "خطای درخواست؛ متن errors برای نمایش و code برای تصمیم برنامه است.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_payload",
                  "errors": [
                    "اطلاعات درخواست را اصلاح کنید."
                  ]
                }
              }
            }
          },
          "409": {
            "description": "خطای درخواست؛ متن errors برای نمایش و code برای تصمیم برنامه است.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_payload",
                  "errors": [
                    "اطلاعات درخواست را اصلاح کنید."
                  ]
                }
              }
            }
          },
          "422": {
            "description": "خطای درخواست؛ متن errors برای نمایش و code برای تصمیم برنامه است.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_payload",
                  "errors": [
                    "اطلاعات درخواست را اصلاح کنید."
                  ]
                }
              }
            }
          },
          "429": {
            "description": "خطای درخواست؛ متن errors برای نمایش و code برای تصمیم برنامه است.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_payload",
                  "errors": [
                    "اطلاعات درخواست را اصلاح کنید."
                  ]
                }
              }
            }
          },
          "503": {
            "description": "خطای درخواست؛ متن errors برای نمایش و code برای تصمیم برنامه است.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_payload",
                  "errors": [
                    "اطلاعات درخواست را اصلاح کنید."
                  ]
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \"$ARTANCLASS_BASE_URL/api/v1/lms/classes\" \\\n  --header \"Authorization: Bearer $ARTANCLASS_API_KEY\" \\\n  --header 'Content-Type: application/json' \\\n  --data-binary @class.json"
          },
          {
            "lang": "JavaScript",
            "label": "Node.js",
            "source": "const { class_url } = await client.createClass(classData);\n// Save class_url with this class in the LMS."
          },
          {
            "lang": "Go",
            "label": "Go",
            "source": "classroom, err := client.CreateClass(ctx, classData)\nif err != nil { /* handle error, then return */ }\n// Save classroom.ClassURL with this class in the LMS."
          }
        ]
      }
    },
    "/api/v1/lms/classes/{external_class_id}/launch": {
      "post": {
        "tags": [
          "ورود"
        ],
        "summary": "۲. دریافت لینک ورود شخص",
        "description": "فقط external_user_id. سرور LMS ابتدا هویت و عضویت را بررسی کند. نقش از کلاس ثبت‌شده تعیین می‌شود. پاسخ لینک شخصی یک‌بارمصرف تا ۱۲۰ ثانیه است. مرورگر همان فرد با 303 به لینک کامل هدایت شود؛ بخش بعد از # حفظ شود. معلم جلسه را شروع می‌کند و دانش‌آموز پیش از او منتظر می‌ماند.",
        "operationId": "launchClass",
        "parameters": [
          {
            "name": "external_class_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,128}$"
            },
            "example": "math-701"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LaunchRequest"
              },
              "example": {
                "external_user_id": "teacher-42"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "فقط لینک شخصی ورود",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LaunchResponse"
                },
                "example": {
                  "entry_url": "https://meet.localhost/sso/launch#ticket=EXAMPLE&browser_nonce=EXAMPLE"
                }
              }
            }
          },
          "400": {
            "description": "خطای درخواست؛ متن errors برای نمایش و code برای تصمیم برنامه است.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_payload",
                  "errors": [
                    "اطلاعات درخواست را اصلاح کنید."
                  ]
                }
              }
            }
          },
          "401": {
            "description": "خطای درخواست؛ متن errors برای نمایش و code برای تصمیم برنامه است.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_payload",
                  "errors": [
                    "اطلاعات درخواست را اصلاح کنید."
                  ]
                }
              }
            }
          },
          "403": {
            "description": "خطای درخواست؛ متن errors برای نمایش و code برای تصمیم برنامه است.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_payload",
                  "errors": [
                    "اطلاعات درخواست را اصلاح کنید."
                  ]
                }
              }
            }
          },
          "404": {
            "description": "خطای درخواست؛ متن errors برای نمایش و code برای تصمیم برنامه است.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_payload",
                  "errors": [
                    "اطلاعات درخواست را اصلاح کنید."
                  ]
                }
              }
            }
          },
          "409": {
            "description": "خطای درخواست؛ متن errors برای نمایش و code برای تصمیم برنامه است.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_payload",
                  "errors": [
                    "اطلاعات درخواست را اصلاح کنید."
                  ]
                }
              }
            }
          },
          "422": {
            "description": "خطای درخواست؛ متن errors برای نمایش و code برای تصمیم برنامه است.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_payload",
                  "errors": [
                    "اطلاعات درخواست را اصلاح کنید."
                  ]
                }
              }
            }
          },
          "429": {
            "description": "خطای درخواست؛ متن errors برای نمایش و code برای تصمیم برنامه است.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_payload",
                  "errors": [
                    "اطلاعات درخواست را اصلاح کنید."
                  ]
                }
              }
            }
          },
          "503": {
            "description": "خطای درخواست؛ متن errors برای نمایش و code برای تصمیم برنامه است.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "code": "invalid_payload",
                  "errors": [
                    "اطلاعات درخواست را اصلاح کنید."
                  ]
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \"$ARTANCLASS_BASE_URL/api/v1/lms/classes/math-701/launch\" \\\n  --header \"Authorization: Bearer $ARTANCLASS_API_KEY\" \\\n  --header 'Content-Type: application/json' \\\n  --data-binary @launch.json"
          },
          {
            "lang": "JavaScript",
            "label": "Node.js",
            "source": "// After LMS authentication and class membership authorization:\nconst { entry_url } = await client.getEntryLink(classId, authenticatedUser.externalId);\nresponse.writeHead(303, {\n  Location: entry_url,\n  'Cache-Control': 'no-store',\n  'Referrer-Policy': 'no-referrer',\n});\nresponse.end();"
          },
          {
            "lang": "Go",
            "label": "Go",
            "source": "// After LMS authentication and class membership authorization:\nentry, err := client.EntryLink(r.Context(), classID, authenticatedUser.ExternalID)\nif err != nil { /* handle error, then return */ }\nw.Header().Set(\"Cache-Control\", \"no-store\")\nw.Header().Set(\"Referrer-Policy\", \"no-referrer\")\nhttp.Redirect(w, r, entry.EntryURL, http.StatusSeeOther)"
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "کلید بخش اتصال به LMS در پنل مدیر ArtanClass"
      }
    },
    "schemas": {
      "Person": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "external_user_id",
          "name",
          "national_id"
        ],
        "properties": {
          "external_user_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "description": "شناسهٔ ثابت شخص در LMS"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "نام و نام خانوادگی"
          },
          "national_id": {
            "type": "string",
            "pattern": "^[0-9]{10}$",
            "description": "کد ملی معتبر با حفظ صفر ابتدا؛ رمز اولیهٔ حساب جدید"
          }
        }
      },
      "ClassRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "external_class_id",
          "name",
          "teacher",
          "students"
        ],
        "properties": {
          "external_class_id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{1,128}$",
            "description": "شناسهٔ ثابت کلاس در LMS"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255
          },
          "teacher": {
            "$ref": "#/components/schemas/Person"
          },
          "students": {
            "type": "array",
            "maxItems": 999,
            "items": {
              "$ref": "#/components/schemas/Person"
            }
          }
        }
      },
      "ClassResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "class_url"
        ],
        "properties": {
          "class_url": {
            "type": "string",
            "format": "uri",
            "description": "لینک دائمی کلاس؛ در LMS ذخیره شود."
          }
        }
      },
      "LaunchRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "external_user_id"
        ],
        "properties": {
          "external_user_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128,
            "description": "شناسهٔ شخص واردشده و مجاز در LMS"
          }
        }
      },
      "LaunchResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "entry_url"
        ],
        "properties": {
          "entry_url": {
            "type": "string",
            "format": "uri",
            "description": "لینک شخصی یک‌بارمصرف با اعتبار ۱۲۰ ثانیه؛ فوراً مرورگر همین شخص را هدایت کنید."
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "code",
          "errors"
        ],
        "properties": {
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      }
    }
  }
}
