Visão Geral de Telemedicina
Gerencia as salas de videochamada (LiveKit) usadas nas consultas online: criação/busca de sala, geração de token de acesso, notificação do paciente via WebSocket, gravação e transcrição.
Todas as rotas exigem o header Authorization: Bearer {accessToken} (JWT do Auth0) ou x-api-key. Veja Autenticação.
Diferente da maioria dos outros módulos, nenhum endpoint de telemedicina usa @CheckPermissions — qualquer usuário autenticado (com qualquer permissão) pode chamar qualquer rota deste módulo, incluindo criar/encerrar salas e ativar gravação.
Base
https://api-dev.imagemais.com.br/api/telemedicine
Rotas
| Método | Rota | Descrição |
|---|---|---|
GET | /telemedicine/room/{consultationId} | Busca a sala LiveKit já criada para a consulta |
POST | /telemedicine/token | Gera um token LiveKit para o usuário atual entrar numa sala |
POST | /telemedicine/room | Cria a sala da consulta (ou retorna a existente) |
POST | /telemedicine/notify | Notifica o paciente (via WebSocket) que a sala está pronta |
DELETE | /telemedicine/delete | Encerra a sala e finaliza a consulta |
POST | /telemedicine/activate-recording | Inicia a gravação (áudio) da sala |
GET | /telemedicine/transcription | Busca a transcrição salva da consulta |
GET | /telemedicine/transcription-preference | Verifica se a transcrição está habilitada para a consulta |
PATCH | /telemedicine/transcription-preference | Habilita/desabilita a transcrição da consulta |
GET | /telemedicine/recording-presigned-url | Gera URL assinada para baixar um arquivo de gravação |
Fluxo típico de uma teleconsulta
- Médico chama
POST /telemedicine/roompara criar a sala (idempotente — se já existe, retorna a mesma). - Médico chama
POST /telemedicine/notify— isso busca/gera um token para o paciente e emitetelemedicine.room.readyvia WebSocket (gateway de pacientes) com o token. Exige que a sala já exista (passo 1). - Médico e paciente entram na sala usando
POST /telemedicine/token(gera o token de cada lado) + SDK do LiveKit no client. - Com participantes conectados, o frontend chama
POST /telemedicine/activate-recordingpara começar a gravar (requer feature flag habilitada e a flagLIVEKIT_ENABLE_RECORDING). - Ao final,
DELETE /telemedicine/deleteencerra a sala no LiveKit, finaliza a consulta (consultationStatus = FINAL) e para qualquer gravação em andamento.
O médico entra com identity = user-{userId} e o paciente com identity = patient-{patientId}. O nome de sala segue o padrão telemedicine-{consultationId}-{consultation.createdAt em ms}.
Notificação ao paciente (WebSocket)
POST /telemedicine/notify não empurra nada por HTTP para o paciente — ele emite eventos internos que o PatientGateway (Socket.io, ver Gateways) repassa para a sala WS do paciente:
| Evento interno | Evento WebSocket (para o paciente) | Payload |
|---|---|---|
patient.room.ready (emitido por notify) | telemedicine.room.ready | { token, timestamp } |
patient.room.closed (emitido por delete) | telemedicine.room.closed | — |
Se o paciente não tiver uma conexão WebSocket ativa (sem "room hash" registrado no gateway), o evento simplesmente não é enviado — só um warn no log do servidor. A resposta HTTP de POST /telemedicine/notify continua { "success": true } mesmo assim, então a API não tem como saber (por essa rota) se o paciente foi de fato avisado.
Gravação
Gravação é somente áudio (audioOnly: true, formato OGG), feita via LiveKit Egress e enviada direto para o Cloudflare R2. Dois egresses são iniciados em paralelo:
- Room composite: uma faixa combinada de toda a sala, salva em
telemedicine/{sha256(consultationId)}/{room_name}. - Por participante: uma faixa de áudio individual por participante conectado, salva em
telemedicine/{sha256(consultationId)}/tracks/{participantName}-{time}.
O consultationId é hasheado (SHA-256) no path do arquivo — não aparece em texto puro no storage.
Transcrição
A transcrição em si (texto) é gerada fora deste módulo e fica salva no campo telemedicineTranscription da consulta — GET /telemedicine/transcription só lê esse campo. A "preferência" de transcrição é um flag independente, guardado no Redis (chave telemedicine:transcription:disabled:{consultationId}, sem TTL), que controla se a geração de transcrição deve rodar para aquela consulta.
GET e PATCH /telemedicine/transcription-preference não verificam se a consulta existe nem se pertence à accountId do token — qualquer usuário autenticado de qualquer conta pode ler ou alterar a preferência de transcrição de um consultationId de outra conta, só adivinhando o número. As demais rotas do módulo (transcription, room, notify, recording-presigned-url etc.) fazem essa checagem corretamente via findConsultation.