Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Renzo717/Aula-Virtual-Universidad-Radiolocucion/llms.txt

Use this file to discover all available pages before exploring further.

The /api/carreras router models the two-level academic hierarchy of NuestraVoz — Campus Virtual: carreras (degree programmes) and their nested materias (subjects). All routes require authentication; admin-only routes additionally enforce the admin role. Deleting either resource is a soft-delete that sets activa: false on the relevant row. Schedule data (horarios) is stored as a structured JSON array and also denormalised into a human-readable horario string via the shared formatHorarios helper. The /api/inscripciones router handles enrollment records for both career and stand-alone subject enrolments.

GET /api/carreras

Returns all active careers, each including their active subjects. Subjects are returned with a nested docente object containing the instructor’s id, nombre, and apellido. Auth: requireAuth — any authenticated role.

Response — 200 OK

data
array
Array of active Carrera objects, ordered alphabetically by nombre.

Example

curl https://api.nuestravoz.edu.ar/api/carreras \
  --cookie "nuestravoz_session=<token>"
{
  "data": [
    {
      "id": "a1b2c3d4-...",
      "nombre": "Locución",
      "codigo": "LOC-G1",
      "tipo": "grado",
      "anio": 1,
      "descripcion": "Primer año de la carrera de Locución.",
      "activa": true,
      "created_at": "2024-02-01T00:00:00.000Z",
      "materias": [
        {
          "id": "f5e6d7c8-...",
          "nombre": "Fonética y Dicción",
          "promocional": true,
          "horario": "lunes 08:00 - 10:00",
          "horarios": [{ "dia": "lunes", "inicio": "08:00", "fin": "10:00" }],
          "zoom_url": "https://zoom.us/j/123456789",
          "activa": true,
          "docente": { "id": "d1d2d3d4-...", "nombre": "Laura", "apellido": "Méndez" }
        }
      ]
    }
  ]
}

GET /api/carreras/:id

Returns a single career record identified by UUID, including all of its active subjects with nested instructor data. Auth: requireAuth — any authenticated role.

Path parameters

id
string
required
UUID of the career to retrieve.

Response — 200 OK

data
object
Full Carrera object. See GET /api/carreras for field descriptions.

Error responses

StatusMeaning
401No valid session cookie.
404Career not found or Supabase query error.

Example

const res = await fetch(
  "https://api.nuestravoz.edu.ar/api/carreras/a1b2c3d4-1234-5678-abcd-ef0123456789",
  { credentials: "include" }
);
const { data } = await res.json();
console.log(data.nombre); // "Locución"

POST /api/carreras

Creates a new career. The codigo and nombre fields are free-form strings; uniqueness is not enforced at the API layer but may be constrained at the database level. Auth: requireAuth + requireRole('admin').

Request body

nombre
string
required
Full career name. Minimum 2 characters.
codigo
string
required
Short code or abbreviation for the career (e.g., LOC-G2). Minimum 2 characters.
tipo
string
required
Degree level. Must be grado or posgrado.
anio
number
required
Academic year of this curriculum block. Integer between 1 and 3 inclusive.
descripcion
string
Optional free-text description of the career.

Response — 201 Created

data
object
The newly created Carrera record.

Error responses

StatusMeaning
400Validation error — see details for Zod field errors.
403Caller is not an admin.

Example

curl -X POST https://api.nuestravoz.edu.ar/api/carreras \
  -H "Content-Type: application/json" \
  --cookie "nuestravoz_session=<admin-token>" \
  -d '{
    "nombre": "Periodismo",
    "codigo": "PER-G1",
    "tipo": "grado",
    "anio": 1,
    "descripcion": "Primer año de Periodismo."
  }'
{
  "data": {
    "id": "b2c3d4e5-...",
    "nombre": "Periodismo",
    "codigo": "PER-G1",
    "tipo": "grado",
    "anio": 1,
    "descripcion": "Primer año de Periodismo.",
    "activa": true,
    "created_at": "2025-03-15T10:00:00.000Z"
  }
}

PATCH /api/carreras/:id

Partially updates an existing career. Send only the fields you wish to change; all createCarreraSchema fields are valid, and the activa flag may also be toggled directly. Auth: requireAuth + requireRole('admin').

Path parameters

id
string
required
UUID of the career to update.

Request body

Any subset of the fields accepted by POST /api/carreras, plus:
activa
boolean
Set to false to deactivate the career (without cascade). Use DELETE /api/carreras/:id to also deactivate all subjects.

Response — 200 OK

data
object
The updated Carrera record.

Example

const res = await fetch(
  "https://api.nuestravoz.edu.ar/api/carreras/b2c3d4e5-...",
  {
    method: "PATCH",
    headers: { "Content-Type": "application/json" },
    credentials: "include",
    body: JSON.stringify({ descripcion: "Descripción actualizada." }),
  }
);
const { data } = await res.json();

DELETE /api/carreras/:id

Deactivates a career and all of its subjects in a single operation by setting activa: false on every related materias row before deactivating the career itself. Auth: requireAuth + requireRole('admin').

Path parameters

id
string
required
UUID of the career to deactivate.

Response — 200 OK

data
object

Example

curl -X DELETE https://api.nuestravoz.edu.ar/api/carreras/a1b2c3d4-... \
  --cookie "nuestravoz_session=<admin-token>"
{
  "data": {
    "message": "Carrera y sus materias desactivadas"
  }
}

POST /api/carreras/materias

Creates a new subject (materia) inside an existing career. Schedule data can be supplied as either a structured horarios array or a legacy horario string; if both are present, the structured array takes precedence and horario is regenerated via formatHorarios. Auth: requireAuth + requireRole('admin').

Request body

carrera_id
string
required
UUID of the parent career. Must be a valid UUID.
nombre
string
required
Subject name. Minimum 2 characters.
promocional
boolean
Whether the subject allows direct promotion (no final exam). Defaults to false.
docente_id
string
UUID of the instructor to assign. Must be a valid UUID.
horarios
array
Array of structured schedule blocks. Each entry must be an object with:
  • dia — one of lunes, martes, miercoles, jueves, viernes, sabado, domingo
  • inicio — start time string in HH:mm format
  • fin — end time string in HH:mm format, must be after inicio
horario
string
Legacy schedule display string in HH:mm - HH:mm format (e.g., "14:00 - 16:00"). Used only when horarios is not provided.
zoom_url
string
Zoom meeting URL for the subject’s virtual classroom. Must be a valid URL or an empty string to clear.
programa_url
string
URL linking to the subject’s programme document (syllabus).

Response — 201 Created

data
object
The newly created Materia record, including the generated horario string.

Error responses

StatusMeaning
400Validation error (invalid UUID, bad time range, etc.).
403Caller is not an admin.

Example

const res = await fetch("https://api.nuestravoz.edu.ar/api/carreras/materias", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  credentials: "include",
  body: JSON.stringify({
    carrera_id: "a1b2c3d4-1234-5678-abcd-ef0123456789",
    nombre: "Producción Radiofónica",
    promocional: false,
    docente_id: "d1d2d3d4-...",
    horarios: [
      { dia: "miercoles", inicio: "14:00", fin: "16:00" }
    ],
    zoom_url: "https://zoom.us/j/987654321",
  }),
});
const { data } = await res.json();
console.log(data.horario); // "miercoles 14:00 - 16:00"

PATCH /api/carreras/materias/:id

Partially updates an existing subject. All fields are optional. Updating horarios automatically recalculates the horario display string. Passing null for docente_id unassigns the instructor. Auth: requireAuth + requireRole('admin', 'preceptor').

Path parameters

id
string
required
UUID of the subject to update.

Request body

nombre
string
Updated subject name. Minimum 2 characters.
promocional
boolean
Updated promotion flag.
docente_id
string | null
Updated instructor UUID. Pass null to unassign.
horarios
array
Updated schedule array. Same structure as in POST. Replaces the existing schedule entirely.
horario
string
Legacy display string in HH:mm - HH:mm format. Accepted only when horarios is not provided.

Response — 200 OK

data
object
The updated Materia record.

Example

curl -X PATCH https://api.nuestravoz.edu.ar/api/carreras/materias/f5e6d7c8-... \
  -H "Content-Type: application/json" \
  --cookie "nuestravoz_session=<token>" \
  -d '{
    "promocional": true,
    "horarios": [{ "dia": "jueves", "inicio": "10:00", "fin": "12:00" }]
  }'

DELETE /api/carreras/materias/:id

Soft-deletes a single subject by setting activa: false. The parent career is unaffected. Auth: requireAuth + requireRole('admin').

Path parameters

id
string
required
UUID of the subject to deactivate.

Response — 200 OK

data
object

Example

curl -X DELETE https://api.nuestravoz.edu.ar/api/carreras/materias/f5e6d7c8-... \
  --cookie "nuestravoz_session=<admin-token>"

GET /api/carreras/docentes/:docenteId/materias

Returns all active subjects assigned to a specific instructor, with the parent career name and year included in each record. Auth: requireAuth + requireRole('admin', 'preceptor').

Path parameters

docenteId
string
required
UUID of the instructor whose subjects are being queried.

Response — 200 OK

data
array
Array of active Materia objects for the given instructor.

Example

const res = await fetch(
  "https://api.nuestravoz.edu.ar/api/carreras/docentes/d1d2d3d4-.../materias",
  { credentials: "include" }
);
const { data } = await res.json();
data.forEach((m) => console.log(m.nombre, "—", m.carrera.nombre));

GET /api/inscripciones/usuario/:userId

Returns all enrollment records for a given user, with expanded career and subject information. Auth: requireAuth + requireRole('admin', 'preceptor').

Path parameters

userId
string
required
UUID of the user whose enrollments are being retrieved.

Response — 200 OK

data
array
Array of Inscripcion records, ordered by created_at descending.

Example

curl https://api.nuestravoz.edu.ar/api/inscripciones/usuario/e3c1a4f0-... \
  --cookie "nuestravoz_session=<token>"

POST /api/inscripciones

Enrolls a user in a career or a stand-alone subject. Either carrera_id or materia_id must be provided, but not necessarily both. The endpoint prevents duplicate active enrolments and validates that the target career or subject exists and is active. Auth: requireAuth + requireRole('admin', 'preceptor').

Request body

user_id
string
required
UUID of the user to enroll.
carrera_id
string
UUID of the career to enroll the user in. Required when enrolling in a career. Must be a valid UUID.
materia_id
string
UUID of the stand-alone subject (a materia with carrera_id = null) to enroll the user in. Required when enrolling in a free-standing course. Must be a valid UUID.

Response — 201 Created

data
object
The newly created Inscripcion record, with expanded carrera or materia data depending on which type of enrolment was created.

Error responses

StatusMeaning
400Validation error, both carrera_id and materia_id absent, career/subject inactive, or duplicate active enrolment.
403Caller is not an admin or preceptor.

Example

// Enroll in a career
const res = await fetch("https://api.nuestravoz.edu.ar/api/inscripciones", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  credentials: "include",
  body: JSON.stringify({
    user_id: "e3c1a4f0-1234-5678-abcd-ef0123456789",
    carrera_id: "a1b2c3d4-1234-5678-abcd-ef0123456789",
  }),
});
const { data } = await res.json();
console.log(data.estado); // "activa"
// Enroll in a stand-alone course subject
const res = await fetch("https://api.nuestravoz.edu.ar/api/inscripciones", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  credentials: "include",
  body: JSON.stringify({
    user_id: "e3c1a4f0-1234-5678-abcd-ef0123456789",
    materia_id: "c9d8e7f6-1234-5678-abcd-ef0123456789",
  }),
});
const { data } = await res.json();
console.log(data.materia.nombre); // "Taller de Voz"

Build docs developers (and LLMs) love