openapi: 3.0.3
info:
  title: TUD CS Catalog API
  description: >
    Public read-only API for the TU Dresden Faculty of Computer Science
    academic catalog. Exposes module and course-schedule data per semester.
  version: 1.0.0

servers:
  - url: /api

paths:
  /semester/{path}:
    get:
      summary: Get semester data
      description: >
        Returns the full module catalog and, when available, the course-schedule
        data for the given semester. The aliases `current` and `upcoming` redirect
        (307) to the canonical semester path.
      operationId: getSemester
      parameters:
        - name: path
          in: path
          required: true
          description: >
            Semester path (e.g. `ws2425`, `ss25`) or the aliases `current` / `upcoming`.
            Aliases respond with a 307 redirect to the canonical path.
          schema:
            type: string
            example: ws2425
      responses:
        "200":
          description: Semester data including module catalog and optional course schedule.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SemesterResponse"
        "307":
          description: >
            Redirect to the canonical path for the aliases `current` or `upcoming`.
          headers:
            Location:
              schema:
                type: string
              description: Canonical semester API URL.
        "404":
          description: Semester path not found.

components:
  schemas:

    # ── Primitives ─────────────────────────────────────────────────────────────

    BiLingual:
      type: object
      description: A string value available in both English and German.
      required: [en, de]
      properties:
        en:
          type: string
        de:
          type: string

    ChoiceOption:
      type: object
      description: A controlled-vocabulary entry with a full term and an abbreviation.
      required: [id, term, abbr]
      properties:
        id:
          type: integer
        term:
          $ref: "#/components/schemas/BiLingual"
        abbr:
          $ref: "#/components/schemas/BiLingual"

    # ── Module catalog (pages.catalog.modules.modules) ─────────────────────────

    DegreeProgram:
      type: object
      required: [id, name]
      properties:
        id:
          type: integer
        name:
          $ref: "#/components/schemas/BiLingual"

    Organisation:
      type: object
      required: [id, name]
      properties:
        id:
          type: integer
        name:
          $ref: "#/components/schemas/BiLingual"

    ModuleEntry:
      type: object
      description: A module as it appears in the catalog (without course-schedule detail).
      required:
        - moduleAlias
        - moduleId
        - moduleNummer
        - name
        - link
        - organisation
        - credits
        - languages
        - erasmus
        - start
        - status
        - content
        - degreePrograms
      properties:
        moduleAlias:
          type: string
          example: INF-B-210
        moduleId:
          type: integer
        moduleNummer:
          type: string
          description: Official module number; may equal moduleAlias.
        campusnetNumber:
          type: string
        responsibleName:
          type: string
        responsibleEmail:
          type: string
          format: email
        name:
          $ref: "#/components/schemas/BiLingual"
        link:
          $ref: "#/components/schemas/BiLingual"
          description: Links to the module description document in each language.
        organisation:
          $ref: "#/components/schemas/Organisation"
        credits:
          type: number
          description: ECTS credit points.
        languages:
          type: array
          items:
            $ref: "#/components/schemas/ChoiceOption"
        erasmus:
          type: array
          items:
            $ref: "#/components/schemas/ChoiceOption"
        start:
          type: array
          description: Semesters in which the module typically starts.
          items:
            $ref: "#/components/schemas/ChoiceOption"
        status:
          $ref: "#/components/schemas/ChoiceOption"
        content:
          $ref: "#/components/schemas/ChoiceOption"
        degreePrograms:
          type: array
          items:
            $ref: "#/components/schemas/DegreeProgram"

    # ── Course schedule (pages.calendar.courses.modules) ───────────────────────

    Room:
      type: object
      nullable: true
      required: [id, name, building, roomSchedule]
      properties:
        id:
          type: integer
        name:
          type: string
        building:
          type: string
        roomSchedule:
          type: string
          description: URL to the room's schedule, if available.

    CourseEntry:
      type: object
      description: A single scheduled course session within a course offering.
      required: [id, required]
      properties:
        id:
          type: integer
        educationalForm:
          nullable: true
          allOf:
            - $ref: "#/components/schemas/ChoiceOption"
        weekday:
          nullable: true
          allOf:
            - $ref: "#/components/schemas/ChoiceOption"
        startTime:
          nullable: true
          allOf:
            - $ref: "#/components/schemas/ChoiceOption"
        duration:
          nullable: true
          allOf:
            - $ref: "#/components/schemas/ChoiceOption"
        frequency:
          nullable: true
          allOf:
            - $ref: "#/components/schemas/ChoiceOption"
        room:
          nullable: true
          allOf:
            - $ref: "#/components/schemas/Room"
        required:
          type: boolean
          description: Whether attendance is mandatory.

    TeacherOrganisation:
      type: object
      nullable: true
      required: [id, abbreviation, name]
      properties:
        id:
          type: integer
        abbreviation:
          type: string
        name:
          $ref: "#/components/schemas/BiLingual"

    TeacherEntry:
      type: object
      required: [id, name, email]
      properties:
        id:
          type: integer
        name:
          type: string
        email:
          type: string
          format: email
        organisation:
          nullable: true
          allOf:
            - $ref: "#/components/schemas/TeacherOrganisation"

    CourseOfferingEntry:
      type: object
      required: [id, name, teachers, courses, languages, url]
      properties:
        id:
          type: integer
        name:
          $ref: "#/components/schemas/BiLingual"
        url:
          type: string
          description: URL to the course offering's page, if available.
        languages:
          type: array
          items:
            $ref: "#/components/schemas/ChoiceOption"
        teachers:
          type: array
          items:
            $ref: "#/components/schemas/TeacherEntry"
        courses:
          type: array
          items:
            $ref: "#/components/schemas/CourseEntry"

    DegreeProgramRef:
      type: object
      description: A degree program reference that includes the recommended study semester.
      required: [id, name, semester]
      properties:
        id:
          type: integer
        name:
          $ref: "#/components/schemas/BiLingual"
        semester:
          type: integer
          description: Recommended study semester within the degree program.

    ModuleWithCourses:
      type: object
      description: >
        A module enriched with its course-schedule offerings for the semester.
        Only present in the response when calendar data is available.
      required:
        - moduleAlias
        - moduleId
        - name
        - organisation
        - credits
        - degreePrograms
        - courseOfferings
      properties:
        moduleAlias:
          type: string
          example: INF-B-210
        moduleId:
          type: integer
        name:
          $ref: "#/components/schemas/BiLingual"
        responsibleName:
          type: string
        responsibleEmail:
          type: string
          format: email
        organisation:
          $ref: "#/components/schemas/Organisation"
        credits:
          type: number
        degreePrograms:
          type: array
          items:
            $ref: "#/components/schemas/DegreeProgramRef"
        courseOfferings:
          type: array
          items:
            $ref: "#/components/schemas/CourseOfferingEntry"

    # ── Top-level response ──────────────────────────────────────────────────────

    SemesterResponse:
      type: object
      required: [semester, modules]
      properties:
        semester:
          $ref: "#/components/schemas/BiLingual"
          description: Display name of the semester.
        modules:
          type: object
          description: >
            Map from module alias (e.g. `INF-B-210`) to module data.
          additionalProperties:
            $ref: "#/components/schemas/ModuleEntry"
        courses:
          type: object
          nullable: true
          description: >
            Map from module alias to module-with-courses data.
            Absent when no calendar data has been published for this semester.
          additionalProperties:
            $ref: "#/components/schemas/ModuleWithCourses"
