{"openapi":"3.0.3","info":{"title":"API GIIS — Consulta Externa","version":"1.1.0","description":"API REST para expedientes médicos electrónicos alineada con la Guía GIIS-B015-04-11 v4.11 del Subsistema de Prestación de Servicios (SIS) — Consulta Externa.\n\n### Módulos\n- **Médicos (Auth):** Registro, login y gestión de sesión JWT\n- **Pacientes:** CRUD con validaciones GIIS\n- **Consultas:** 106 variables GIIS-B015-04-11\n- **Consultas Globales:** Búsqueda y filtrado de consultas de todos los pacientes\n- **Citas:** Agendamiento y seguimiento\n- **Antecedentes:** Historial clínico\n- **Adendums:** Notas adicionales del expediente\n- **Documentos Clínicos:** Historial de consentimientos y documentos generados por paciente\n- **Plantillas de Documentos:** Consentimientos y documentos clínicos personalizados\n- **Mis Medicamentos:** Catálogo personal de medicamentos del médico\n- **KPI:** Dashboard de indicadores propios del médico (pacientes, consultas, citas, CURP, fusiones, tickets, almacenamiento)\n- **Sedes:** Centros de operación\n- **Manager:** Plataforma de gestión institucional\n\n### Descarga OpenAPI\n`GET /api/docs.json` — Descarga el spec completo en JSON","contact":{"name":"Soporte","email":"soporte@ejemplo.com"}},"servers":[{"url":"http://localhost:3000","description":"Desarrollo"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Ingresa tu access token JWT (médico)"},"managerBearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Ingresa tu access token JWT (manager)"},"crmBearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Ingresa tu access token JWT (CRM admin)"}},"schemas":{"LoginRequest":{"type":"object","required":["correo","password"],"properties":{"correo":{"type":"string","example":"doctor@ejemplo.com"},"password":{"type":"string","example":"MiPassword123"}}},"LoginResponse":{"type":"object","properties":{"accessToken":{"type":"string"},"refreshToken":{"type":"string"},"medico":{"type":"object","properties":{"id_medico":{"type":"integer"},"nombrePrestador":{"type":"string"},"primerApellidoPrestador":{"type":"string"},"tipoPersonal":{"type":"integer"},"displayname":{"type":"string"},"correo":{"type":"string"}}}}},"RefreshRequest":{"type":"object","required":["refreshToken"],"properties":{"refreshToken":{"type":"string"}}},"RegisterRequest":{"type":"object","required":["nombrePrestador","primerApellidoPrestador","curpPrestador","tipoPersonal","paisNacimiento","correo","password","cedula_profesional","id_especialidad"],"properties":{"nombrePrestador":{"type":"string","maxLength":50,"description":"GIIS#4 Solo A-Z, Ñ mayúsculas","example":"JUAN"},"primerApellidoPrestador":{"type":"string","maxLength":50,"description":"GIIS#5","example":"PEREZ"},"segundoApellidoPrestador":{"type":"string","maxLength":50,"description":"GIIS#6 \"XX\" si no tiene","example":"LOPEZ"},"curpPrestador":{"type":"string","minLength":18,"maxLength":18,"description":"GIIS#3 CURP del prestador","example":"PELJ850101HDFRPN09"},"tipoPersonal":{"type":"integer","description":"GIIS#7 Catálogo TIPO PERSONAL-SIS","example":2},"paisNacimiento":{"type":"integer","description":"GIIS#2 Catálogo PAIS","example":142},"correo":{"type":"string","format":"email","example":"doctor@ejemplo.com"},"password":{"type":"string","minLength":8,"example":"MiPassword123"},"telefono":{"type":"string","example":"5551234567"},"displayname":{"type":"string","example":"Dr. Juan"},"sexo":{"type":"integer","enum":[1,2],"example":1},"genero":{"type":"integer","enum":[0,1,2,3,4,5,6,88],"example":1},"fecha_nacimiento":{"type":"string","format":"date","example":"1985-01-01"},"cedula_profesional":{"type":"string","example":"12345678"},"id_especialidad":{"type":"integer","example":1}}},"PacienteCreate":{"type":"object","required":["nombre","primerApellido","curpPaciente","sexoCurp","sexoBiologico","genero","derechohabiencia","fechaNacimiento"],"properties":{"nombre":{"type":"string","maxLength":50,"description":"GIIS#10 Solo A-Z, Ñ mayúsculas. CONFIDENCIAL","example":"MARIA"},"primerApellido":{"type":"string","maxLength":50,"description":"GIIS#11 \"XX\" si no tiene","example":"GARCIA"},"segundoApellido":{"type":"string","maxLength":50,"description":"GIIS#12 \"XX\" si no tiene","example":"HERNANDEZ"},"curpPaciente":{"type":"string","minLength":18,"maxLength":18,"description":"GIIS#9 CURP del paciente. Genérico: XXXX999999XXXXXX99","example":"GAHM900215MDFRRR01"},"sexoCurp":{"type":"integer","enum":[1,2,3],"description":"GIIS#16 1=Hombre, 2=Mujer, 3=No binario","example":2},"sexoBiologico":{"type":"integer","enum":[1,2,3],"description":"GIIS#17 1=Hombre, 2=Mujer, 3=Intersexual","example":2},"genero":{"type":"integer","enum":[0,1,2,3,4,5,6,88],"description":"GIIS#22 Identidad de género","example":2},"fechaNacimiento":{"type":"string","format":"date-time","description":"GIIS#13 dd/mm/aaaa o ISO","example":"1990-02-15T00:00:00Z"},"entidadNacimiento":{"type":"string","maxLength":2,"description":"GIIS#15 Catálogo ENTIDAD FEDERATIVA. 88=Extranjero, 99=Se ignora","example":"09"},"paisNacPaciente":{"type":"string","description":"GIIS#14 Catálogo PAIS","example":"142"},"derechohabiencia":{"type":"string","description":"GIIS#23 Valores separados por &","example":"1"},"seConsideraIndigena":{"type":"integer","enum":[-1,0,1,2,3],"description":"GIIS#19","example":0},"seAutodenominaAfromexicano":{"type":"integer","enum":[-1,0,1,2,3],"description":"GIIS#18","example":0},"migrante":{"type":"integer","enum":[-1,0,1,2,3],"description":"GIIS#20","example":0},"paisProcedencia":{"type":"string","description":"GIIS#21","example":"-1"},"telefono":{"type":"string","example":"5559876543"},"correo":{"type":"string","format":"email","example":"paciente@ejemplo.com"},"calle":{"type":"string","example":"AV REFORMA"},"colonia":{"type":"string","example":"CENTRO"},"municipio":{"type":"string","example":"CUAUHTEMOC"},"estado":{"type":"string","example":"CDMX"},"cpostal":{"type":"string","example":"06000"},"estado_civil":{"type":"string","example":"SOLTERO"},"ocupacion":{"type":"string","example":"EMPLEADO"}}},"PacienteResponse":{"type":"object","properties":{"id_paciente":{"type":"integer"},"nombre":{"type":"string"},"primerApellido":{"type":"string"},"segundoApellido":{"type":"string"},"curpPaciente":{"type":"string"},"fechaNacimiento":{"type":"string","format":"date-time"},"sexoBiologico":{"type":"integer"},"sexoCurp":{"type":"integer"},"genero":{"type":"integer"},"derechohabiencia":{"type":"string"},"telefono":{"type":"string"},"correo":{"type":"string"},"status":{"type":"integer"},"fecha":{"type":"string","format":"date-time"},"actualizacion":{"type":"string","format":"date-time"}}},"PacienteListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PacienteResponse"}},"total":{"type":"integer"},"page":{"type":"integer"},"limit":{"type":"integer"}}},"ConsultaCreate":{"type":"object","required":["codigoCIEDiagnostico1","relacionTemporal"],"properties":{"motivo":{"type":"string","description":"Motivo de la consulta","example":"Dolor de cabeza recurrente"},"relacionTemporal":{"type":"string","enum":["0","1"],"description":"GIIS#42 0=Primera vez, 1=Subsecuente","example":"0"},"padecimiento_actual":{"type":"string","example":"Cefalea de 3 días de evolución"},"exploracion_fisica":{"type":"string","example":"Paciente orientado, consciente"},"plan":{"type":"string","example":"Paracetamol 500mg c/8h"},"peso":{"type":"string","description":"GIIS#26 Kg. 1-400, 999=desconoce","example":"70.5"},"talla":{"type":"string","description":"GIIS#27 cm. 30-220, 999=desconoce","example":"170"},"circunferenciaCintura":{"type":"string","description":"GIIS#28 cm. 20-300, 0=desconoce","example":"85"},"sistolica":{"type":"string","description":"GIIS#29 mmHg. 50-300, 0=desconoce","example":"120"},"diastolica":{"type":"string","description":"GIIS#30 mmHg. 20-200, 0=desconoce","example":"80"},"frecuenciaCardiaca":{"type":"string","description":"GIIS#31 lpm. 40-220, 0=desconoce","example":"72"},"frecuenciaRespiratoria":{"type":"string","description":"GIIS#32 rpm. 10-99, 0=desconoce","example":"18"},"temperatura":{"type":"string","description":"GIIS#33 °C. 30-44, 0=desconoce","example":"36.5"},"saturacionOxigeno":{"type":"string","description":"GIIS#34 SpO2 %. 1-100, 0=desconoce","example":"98"},"glucemia":{"type":"string","description":"GIIS#35 mg/dl. 20-999, 0=desconoce","example":"0"},"tipoMedicion":{"type":"string","description":"GIIS#36 0=No, 1=Sí(ayunas), -1=N/A","example":"-1"},"resultadoObtenidoaTravesde":{"type":"string","description":"GIIS#37 1=Lab, 2=Tira capilar, -1=N/A","example":"-1"},"servicioAtencion":{"type":"string","description":"GIIS#25 Catálogo SERVICIOS DE ATENCIÓN","example":"1"},"codigoCIEDiagnostico1":{"type":"string","maxLength":4,"minLength":4,"description":"GIIS#43 Código CIE-10 4 chars","example":"R519"},"descripcionDiagnostico1":{"type":"string","example":"Cefalea no especificada"},"confirmacionDiagnostico1":{"type":"string","description":"GIIS#44 1=Sí, 0=No, -1=N/A","example":"-1"},"primeraVezDiagnostico2":{"type":"integer","description":"GIIS#45 0=No, 1=Sí, -1=N/A","example":-1},"codigoCIEDiagnostico2":{"type":"string","description":"GIIS#46 Vacío si dx2 N/A","example":""},"primeraVezDiagnostico3":{"type":"integer","description":"GIIS#48","example":-1},"codigoCIEDiagnostico3":{"type":"string","description":"GIIS#49","example":""},"intervencionesSMyA":{"type":"string","description":"GIIS#51 1=Psicosocial, 2=Farmacológico, 3=Ambos, -1=N/A","example":"-1"},"atencionPregestacionalRT":{"type":"string","description":"GIIS#52 0=1ra vez, 1=Subsec, -1=N/A","example":"-1"},"relacionTemporalEmbarazo":{"type":"string","description":"GIIS#54","example":"-1"},"puerpera":{"type":"string","description":"GIIS#68","example":"-1"},"ninoSanoRT":{"type":"string","description":"GIIS#77 -1=N/A","example":"-1"},"edasRT":{"type":"string","description":"GIIS#81 -1=N/A","example":"-1"},"irasRT":{"type":"string","description":"GIIS#85 -1=N/A","example":"-1"},"sintomaDepresiva":{"type":"string","description":"GIIS#90 -1=N/A","example":"-1"},"referidoPor":{"type":"string","description":"GIIS#101 -1=N/A","example":"-1"},"contrarreferido":{"type":"string","description":"GIIS#102 0=No, 1=Sí","example":"0"},"telemedicina":{"type":"string","description":"GIIS#103 0=No, 1=Sí","example":"0"},"teleconsulta":{"type":"string","description":"GIIS#104 0=No, 1=Sí","example":"0"},"lineaVida":{"type":"string","description":"GIIS#98 0=No, 1=Sí","example":"0"},"cartillaSalud":{"type":"string","description":"GIIS#99 0=No, 1=Sí","example":"0"},"esquemaVacunacion":{"type":"string","description":"GIIS#100 0=No, 1=Sí","example":"1"},"prescripciones":{"type":"array","items":{"type":"object","properties":{"medicamento":{"type":"string","example":"Paracetamol 500mg"},"dosis":{"type":"string","example":"1 tableta"},"via":{"type":"string","example":"Oral"},"duracion":{"type":"string","example":"5 días"},"comentarios":{"type":"string","example":"Cada 8 horas"}}}},"ordenes":{"type":"array","items":{"type":"object","properties":{"tipo":{"type":"string","example":"laboratorio"},"orden":{"type":"string","example":"BH completa, QS"}}}}}},"ConsultaGlobalResponse":{"type":"object","properties":{"id_consulta":{"type":"integer","example":130},"nombre":{"type":"string","example":"ANDREA"},"primerApellido":{"type":"string","example":"VARGAS"},"segundoApellido":{"type":"string","example":"VIDAL"},"motivo":{"type":"string","example":"PRUEBA"},"consultorio":{"type":"string","example":"CRIT Tlalnepantla"},"fechaConsulta":{"type":"string","format":"date-time","example":"2026-03-04T17:27:44.000Z"}}},"CitaCreate":{"type":"object","required":["id_paciente","fecha_cita"],"properties":{"id_paciente":{"type":"integer","example":1},"titulo":{"type":"string","example":"Consulta de seguimiento"},"observaciones":{"type":"string","example":"Traer resultados de laboratorio"},"fecha_cita":{"type":"string","format":"date-time","example":"2026-03-01T10:00:00Z"},"correo":{"type":"string","example":"paciente@ejemplo.com"},"tipo":{"type":"string","enum":["presencial","telemedicina"],"example":"presencial"},"recordatorios":{"type":"integer","enum":[0,1],"example":1}}},"AntecedenteCreate":{"type":"object","required":["tipo","antecedente"],"properties":{"tipo":{"type":"string","enum":["familiar","personal","patologico","no_patologico","ginecologico","quirurgico","alergias","otros"],"example":"patologico"},"antecedente":{"type":"string","example":"Diabetes Mellitus tipo 2"},"observacion":{"type":"string","example":"Diagnosticada hace 5 años, en tratamiento con metformina"}}},"AdendumCreate":{"type":"object","required":["nota"],"properties":{"nota":{"type":"string","example":"Paciente refiere mejoría tras ajuste de dosis."}}},"AdendumResponse":{"type":"object","properties":{"id_adendum":{"type":"integer","example":1},"id_medico":{"type":"integer","example":12},"id_paciente":{"type":"integer","example":4},"nota":{"type":"string","example":"Paciente refiere mejoría tras ajuste de dosis."},"fecha":{"type":"string","format":"date-time","example":"2025-06-01T10:30:00.000Z"},"actualizacion":{"type":"string","format":"date-time","example":"2025-06-01T10:30:00.000Z"},"nombrePrestador":{"type":"string","example":"Dr. Juan Pérez"}}},"PacienteDocumentoCreate":{"type":"object","required":["tipo","titulo","texto_final"],"properties":{"tipo":{"type":"string","enum":["consentimiento_informado","aviso_privacidad","alta_voluntaria","rechazo_tratamiento","consentimiento_cirugia","consentimiento_anestesia","consentimiento_procedimiento","otro"],"description":"Mismo valor que medico__documento_config.tipo","example":"consentimiento_informado"},"titulo":{"type":"string","maxLength":150,"description":"Copia del título en el momento de generación","example":"Consentimiento Informado para Cirugía de Cataratas"},"texto_final":{"type":"string","description":"Texto ya con variables sustituidas al momento de generar","example":"Yo, María García Hernández, autorizo al Dr. Juan Pérez a realizar el procedimiento indicado el 24/02/2026."},"id_consulta":{"type":"integer","nullable":true,"description":"FK opcional → paciente__consulta.id_consulta","example":42},"observaciones":{"type":"string","nullable":true,"description":"Notas adicionales del médico","example":"Paciente firmó con testigo presente."}}},"PacienteDocumentoResponse":{"type":"object","properties":{"id_documento":{"type":"integer","example":15},"id_paciente":{"type":"integer","example":7},"id_medico":{"type":"integer","example":12},"id_consulta":{"type":"integer","nullable":true,"example":42},"tipo":{"type":"string","example":"consentimiento_informado"},"titulo":{"type":"string","example":"Consentimiento Informado para Cirugía de Cataratas"},"texto_final":{"type":"string","example":"Yo, María García Hernández, autorizo al Dr. Juan Pérez..."},"firmado":{"type":"integer","enum":[0,1],"description":"0=Solo generado, 1=Firmado por el paciente","example":0},"fecha_firma":{"type":"string","format":"date-time","nullable":true,"example":null},"observaciones":{"type":"string","nullable":true,"example":"Paciente firmó con testigo presente."},"status":{"type":"integer","enum":[0,1],"description":"0=Anulado, 1=Vigente","example":1},"fecha":{"type":"string","format":"date-time","example":"2026-02-24T18:00:00.000Z"},"actualizacion":{"type":"string","format":"date-time","example":"2026-02-24T18:00:00.000Z"},"nombreMedico":{"type":"string","example":"Juan Pérez"}}},"DocumentoConfigCreate":{"type":"object","required":["tipo","titulo","texto"],"properties":{"tipo":{"type":"string","enum":["consentimiento_informado","aviso_privacidad","alta_voluntaria","rechazo_tratamiento","consentimiento_cirugia","consentimiento_anestesia","consentimiento_procedimiento","otro"],"description":"Categoría del documento clínico","example":"consentimiento_informado"},"titulo":{"type":"string","maxLength":150,"description":"Título que aparece en el documento impreso","example":"Consentimiento Informado para Cirugía de Cataratas"},"texto":{"type":"string","description":"Cuerpo del documento. Variables soportadas: {{NOMBRE_PACIENTE}}, {{MEDICO}}, {{FECHA}}, {{ESPECIALIDAD}}","example":"Yo, {{NOMBRE_PACIENTE}}, autorizo al {{MEDICO}} a realizar el procedimiento indicado en fecha {{FECHA}}."},"activo":{"type":"integer","enum":[0,1],"default":1,"description":"0=Desactivado, 1=Activo","example":1}}},"DocumentoConfigUpdate":{"type":"object","properties":{"tipo":{"type":"string","enum":["consentimiento_informado","aviso_privacidad","alta_voluntaria","rechazo_tratamiento","consentimiento_cirugia","consentimiento_anestesia","consentimiento_procedimiento","otro"],"example":"aviso_privacidad"},"titulo":{"type":"string","maxLength":150,"example":"Aviso de Privacidad"},"texto":{"type":"string","example":"Sus datos serán tratados conforme a la Ley Federal de Protección de Datos."},"activo":{"type":"integer","enum":[0,1],"example":1}}},"DocumentoConfigResponse":{"type":"object","properties":{"id_config":{"type":"integer","example":1},"id_medico":{"type":"integer","example":12},"tipo":{"type":"string","example":"consentimiento_informado"},"titulo":{"type":"string","example":"Consentimiento Informado para Cirugía de Cataratas"},"texto":{"type":"string","example":"Yo, {{NOMBRE_PACIENTE}}, autorizo al {{MEDICO}}..."},"activo":{"type":"integer","enum":[0,1],"example":1},"fecha":{"type":"string","format":"date-time","example":"2026-02-24T18:00:00.000Z"},"actualizacion":{"type":"string","format":"date-time","example":"2026-02-24T18:00:00.000Z"}}},"MisMedicamentosCreate":{"type":"object","required":["nombre"],"properties":{"nombre":{"type":"string","example":"Vaporub"},"formula":{"type":"string","example":"Mentol, Alcanfor, Eucalipto"},"presentacion":{"type":"string","example":"Ungüento"},"gramaje":{"type":"string","example":"12 g"},"via":{"type":"string","example":"Tópica"}}},"MisMedicamentosResponse":{"type":"object","properties":{"id_medicamento":{"type":"integer","example":1},"id_medico":{"type":"integer","example":12},"nombre":{"type":"string","example":"Vaporub"},"formula":{"type":"string","example":"Mentol, Alcanfor, Eucalipto"},"presentacion":{"type":"string","example":"Ungüento"},"gramaje":{"type":"string","example":"12 g"},"via":{"type":"string","example":"Tópica"},"fecha":{"type":"string","format":"date-time","example":"2026-03-01T10:00:00.000Z"},"actualizacion":{"type":"string","format":"date-time","example":"2026-03-01T10:00:00.000Z"}}},"MisMedicamentosListResponse":{"type":"object","properties":{"ok":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/MisMedicamentosResponse"}}}},"SedeCreate":{"type":"object","required":["id_institucion","nombre"],"properties":{"id_institucion":{"type":"integer","example":1},"nombre":{"type":"string","example":"Consultorio Principal"},"clave":{"type":"string","example":"CONS-01"},"clues":{"type":"string","minLength":11,"maxLength":11,"description":"GIIS#1 CLUES 11 caracteres. NULL si no aplica","example":"DFSSA000123"},"tipo_establecimiento":{"type":"string","example":"CS"},"calle":{"type":"string","example":"AV INSURGENTES SUR 1234"},"colonia":{"type":"string","example":"DEL VALLE"},"municipio":{"type":"string","example":"BENITO JUAREZ"},"estado":{"type":"string","example":"CIUDAD DE MEXICO"},"c_postal":{"type":"string","example":"03100"},"telefono":{"type":"string","example":"5551234567"},"zona_horaria":{"type":"string","example":"America/Mexico_City"},"latitud":{"type":"number","format":"double","minimum":-90,"maximum":90,"nullable":true,"description":"Latitud en grados decimales","example":19.4326077},"longitud":{"type":"number","format":"double","minimum":-180,"maximum":180,"nullable":true,"description":"Longitud en grados decimales","example":-99.133208}}},"ManagerLoginRequest":{"type":"object","required":["correo","password"],"properties":{"correo":{"type":"string","format":"email","example":"admin@institucion.com"},"password":{"type":"string","example":"MiPassword123"},"recaptchaToken":{"type":"string","description":"Token reCAPTCHA Enterprise (opcional)"}}},"ManagerLoginResponse":{"type":"object","properties":{"accessToken":{"type":"string"},"refreshToken":{"type":"string"},"manager":{"type":"object","properties":{"id_manager":{"type":"integer"},"nombre":{"type":"string"},"apellido_paterno":{"type":"string"},"apellido_materno":{"type":"string"},"correo":{"type":"string"},"rol":{"type":"string","enum":["superadmin","admin","viewer"]},"id_institucion":{"type":"integer"},"institucion_nombre":{"type":"string"},"centros":{"type":"array","items":{"type":"object","properties":{"id_sede":{"type":"integer"},"nombre":{"type":"string"},"clave":{"type":"string"},"permisos":{"type":"string"}}}}}}}},"ManagerRegisterInstitutionRequest":{"type":"object","required":["institucion_nombre","nombre","apellido_paterno","correo","password"],"properties":{"institucion_nombre":{"type":"string","example":"Clínica San Ángel"},"razon_social":{"type":"string","example":"Clínica San Ángel SA de CV"},"rfc":{"type":"string","example":"CSA2101016A1"},"contacto_nombre":{"type":"string","example":"Dr. Responsable"},"contacto_correo":{"type":"string","format":"email","example":"contacto@clinica.com"},"contacto_telefono":{"type":"string","example":"5551234567"},"nombre":{"type":"string","example":"CARLOS"},"apellido_paterno":{"type":"string","example":"RAMIREZ"},"apellido_materno":{"type":"string","example":"GOMEZ"},"correo":{"type":"string","format":"email","example":"admin@clinica.com"},"password":{"type":"string","minLength":8,"example":"MiPassword123"},"telefono":{"type":"string","example":"5559876543"},"recaptchaToken":{"type":"string","description":"Token reCAPTCHA Enterprise (opcional)"}}},"ManagerRegisterRequest":{"type":"object","required":["nombre","apellido_paterno","correo","password"],"properties":{"nombre":{"type":"string","example":"ANA"},"apellido_paterno":{"type":"string","example":"LOPEZ"},"apellido_materno":{"type":"string","example":"MARTINEZ"},"correo":{"type":"string","format":"email","example":"manager@institucion.com"},"password":{"type":"string","minLength":8,"example":"MiPassword123"},"telefono":{"type":"string","example":"5551234567"},"rol":{"type":"string","enum":["superadmin","admin","viewer"],"default":"admin","example":"admin"},"centros_ids":{"type":"array","description":"IDs de sedes o objetos {id_sede, permisos}","items":{"oneOf":[{"type":"integer","example":1},{"type":"object","properties":{"id_sede":{"type":"integer","example":1},"permisos":{"type":"string","example":"ver_medicos,editar_medicos,ver_reportes"}}}]}}}},"ManagerUpdateRequest":{"type":"object","properties":{"nombre":{"type":"string","example":"ANA MARIA"},"apellido_paterno":{"type":"string","example":"LOPEZ"},"apellido_materno":{"type":"string","example":"MARTINEZ"},"telefono":{"type":"string","example":"5551234567"},"rol":{"type":"string","enum":["superadmin","admin","viewer"],"description":"Solo superadmin puede cambiar"},"status":{"type":"integer","enum":[0,1],"description":"0=Inactivo, 1=Activo"},"centros_ids":{"type":"array","items":{"oneOf":[{"type":"integer"},{"type":"object","properties":{"id_sede":{"type":"integer"},"permisos":{"type":"string"}}}]}}}},"ManagerCentroCreate":{"type":"object","required":["nombre"],"properties":{"nombre":{"type":"string","example":"Sucursal Norte"},"clave":{"type":"string","example":"SUC-N01"},"clues":{"type":"string","minLength":11,"maxLength":11,"description":"CLUES 11 caracteres","example":"DFSSA000456"},"tipo_establecimiento":{"type":"string","example":"CS"},"es_principal":{"type":"integer","enum":[0,1],"default":0},"calle":{"type":"string","example":"AV INSURGENTES NORTE 500"},"no_exterior":{"type":"string","example":"500"},"no_interior":{"type":"string","example":"A"},"colonia":{"type":"string","example":"SANTA MARIA LA RIBERA"},"municipio":{"type":"string","example":"CUAUHTEMOC"},"estado":{"type":"string","example":"CIUDAD DE MEXICO"},"c_postal":{"type":"string","example":"06400"},"telefono":{"type":"string","example":"5551234567"},"correo":{"type":"string","format":"email","example":"sucursal@clinica.com"},"zona_horaria":{"type":"string","default":"America/Mexico_City","example":"America/Mexico_City"},"color":{"type":"string","example":"#3B82F6"}}},"ManagerMedicoCreate":{"type":"object","required":["nombrePrestador","primerApellidoPrestador","correo","password","curpPrestador"],"properties":{"nombrePrestador":{"type":"string","maxLength":50,"example":"JUAN"},"primerApellidoPrestador":{"type":"string","maxLength":50,"example":"PEREZ"},"segundoApellidoPrestador":{"type":"string","maxLength":50,"example":"LOPEZ"},"curpPrestador":{"type":"string","minLength":18,"maxLength":18,"example":"PELJ850101HDFRPN09"},"tipoPersonal":{"type":"integer","example":2},"correo":{"type":"string","format":"email","example":"doctor@clinica.com"},"password":{"type":"string","minLength":8,"example":"MiPassword123"},"telefono":{"type":"string","example":"5551234567"},"sexo":{"type":"integer","enum":[1,2],"example":1},"genero":{"type":"integer","example":0},"fecha_nacimiento":{"type":"string","format":"date","example":"1985-01-01"},"cedula_profesional":{"type":"string","example":"12345678"},"id_especialidad":{"type":"integer","example":1},"id_sede":{"type":"integer","description":"Sede a la que se vinculará el médico","example":1},"c_postal":{"type":"string","example":"06000"},"estado":{"type":"string","example":"CDMX"},"municipio":{"type":"string","example":"CUAUHTEMOC"},"colonia":{"type":"string","example":"CENTRO"},"calle":{"type":"string","example":"AV REFORMA"}}},"DashboardSummary":{"type":"object","properties":{"medicos_activos":{"type":"integer","example":15},"centros":{"type":"integer","example":3},"consultas_mes":{"type":"integer","example":245},"pacientes":{"type":"integer","example":1200}}},"DashboardUsage":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"anio":{"type":"integer","example":2026},"mes":{"type":"integer","example":2},"consultas":{"type":"integer","example":120},"pacientes":{"type":"integer","example":45},"citas":{"type":"integer","example":80}}}}}},"KpiResumenResponse":{"type":"object","properties":{"total_pacientes":{"type":"integer","example":28},"total_consultas":{"type":"integer","example":32},"citas_completadas":{"type":"integer","example":18},"citas_canceladas":{"type":"integer","example":4},"citas_pendientes":{"type":"integer","example":3},"citas_confirmadas":{"type":"integer","example":2}}},"KpiCitasSemanaResponse":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"dia":{"type":"string","format":"date","example":"2026-03-10"},"nombre_dia":{"type":"string","example":"Tuesday"},"total_citas":{"type":"integer","example":6},"completadas":{"type":"integer","example":5},"canceladas":{"type":"integer","example":1}}}}}},"KpiCurpResponse":{"type":"object","properties":{"total_pacientes":{"type":"integer","example":28},"con_curp":{"type":"integer","example":21},"sin_curp":{"type":"integer","example":7}}},"KpiFusionesResponse":{"type":"object","properties":{"total_solicitudes":{"type":"integer","example":5},"fusiones_completadas":{"type":"integer","example":3},"fusiones_pendientes":{"type":"integer","example":1},"fusiones_rechazadas":{"type":"integer","example":1}}},"KpiTicketsResponse":{"type":"object","properties":{"total_tickets":{"type":"integer","example":4},"abiertos":{"type":"integer","example":1},"en_proceso":{"type":"integer","example":1},"cerrados":{"type":"integer","example":2}}},"KpiAlmacenamientoResponse":{"type":"object","properties":{"total_archivos":{"type":"integer","example":26},"bytes_usados":{"type":"integer","example":15728640},"mb_usados":{"type":"number","example":15}}},"KpiMedicamentosResponse":{"type":"object","properties":{"total_medicamentos":{"type":"integer","example":12}}},"InstitucionUpdate":{"type":"object","properties":{"nombre":{"type":"string","example":"Clínica San Ángel"},"razon_social":{"type":"string","example":"Clínica San Ángel SA de CV"},"rfc":{"type":"string","example":"CSA2101016A1"},"logo":{"type":"string","description":"URL del logo"},"compartir_pacientes":{"type":"integer","enum":[0,1]},"contacto_nombre":{"type":"string"},"contacto_correo":{"type":"string","format":"email"},"contacto_telefono":{"type":"string"}}},"CrmLoginRequest":{"type":"object","required":["correo","llave"],"properties":{"correo":{"type":"string","format":"email","example":"admin@januxmd.com"},"llave":{"type":"string","example":"SuperSecretPassword"}}},"CrmLoginResponse":{"type":"object","properties":{"accessToken":{"type":"string"},"refreshToken":{"type":"string"},"admin":{"type":"object","properties":{"id_admin":{"type":"integer"},"nombre":{"type":"string"},"correo":{"type":"string"},"rol":{"type":"string","enum":["owner","admin","soporte","viewer"]}}}}},"CrmAdminProfile":{"type":"object","properties":{"admin":{"type":"object","properties":{"id_admin":{"type":"integer"},"nombre":{"type":"string"},"correo":{"type":"string"},"rol":{"type":"string"},"avatar":{"type":"string","nullable":true},"ultimo_acceso":{"type":"string","format":"date-time"},"status":{"type":"integer"},"fecha":{"type":"string","format":"date-time"}}}}},"CrmGlobalStats":{"type":"object","properties":{"total_instituciones":{"type":"integer","example":12},"instituciones_inactivas":{"type":"integer","example":1},"total_medicos":{"type":"integer","example":17},"medicos_entity":{"type":"integer","example":14},"medicos_individual":{"type":"integer","example":3},"total_pacientes":{"type":"integer","example":342},"total_sedes":{"type":"integer","example":28},"suscripciones_activas":{"type":"integer","example":8},"suscripciones_trial":{"type":"integer","example":3},"suscripciones_vencidas":{"type":"integer","example":1},"ingresos_mes_actual":{"type":"number","example":4680},"tickets_abiertos":{"type":"integer","example":4},"cedulas_pendientes":{"type":"integer","example":1}}},"CrmInstitucionCreate":{"type":"object","required":["nombre"],"properties":{"nombre":{"type":"string","example":"Hospital Angeles Puebla"},"tipo":{"type":"string","enum":["individual","entidad"],"example":"entidad"},"razon_social":{"type":"string","example":"Grupo Angeles S.A."},"rfc":{"type":"string","example":"GAS950101XXX"},"max_sedes":{"type":"integer","example":5},"max_medicos":{"type":"integer","example":10},"contacto_nombre":{"type":"string","example":"Carlos Rodríguez"},"contacto_correo":{"type":"string","format":"email","example":"carlos@hospital.com"},"contacto_telefono":{"type":"string","example":"5551234567"}}},"CrmInstitucionUpdate":{"type":"object","properties":{"nombre":{"type":"string"},"tipo":{"type":"string","enum":["individual","entidad"]},"razon_social":{"type":"string"},"rfc":{"type":"string"},"max_sedes":{"type":"integer"},"max_medicos":{"type":"integer"},"compartir_pacientes":{"type":"integer","enum":[0,1]},"contacto_nombre":{"type":"string"},"contacto_correo":{"type":"string"},"contacto_telefono":{"type":"string"},"status":{"type":"integer","enum":[0,1,2]}}},"CrmPlanCreate":{"type":"object","required":["nombre","clave"],"properties":{"nombre":{"type":"string","example":"Professional"},"clave":{"type":"string","example":"professional"},"precio_mensual":{"type":"number","example":520},"precio_anual":{"type":"number","example":5200},"max_centros":{"type":"integer","example":3},"max_medicos":{"type":"integer","example":5},"max_registros_mes":{"type":"integer","example":2000},"features":{"type":"object","description":"JSON de features habilitadas"}}},"CrmTicketReply":{"type":"object","required":["comment"],"properties":{"comment":{"type":"string","example":"Hemos identificado el problema y lo estamos solucionando."}}},"CrmCedulaReject":{"type":"object","properties":{"motivo":{"type":"string","example":"Cédula no coincide con nombre registrado"}}},"Error":{"type":"object","properties":{"error":{"type":"string"},"detalles":{"type":"array","items":{"type":"string"}}}},"MessageResponse":{"type":"object","properties":{"message":{"type":"string"}}},"PaginatedResponse":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object"}},"total":{"type":"integer"},"page":{"type":"integer"},"limit":{"type":"integer"},"pages":{"type":"integer"}}}}},"security":[{"bearerAuth":[]}],"tags":[{"name":"Auth","description":"Autenticación y registro de médicos"},{"name":"Pacientes","description":"CRUD de pacientes con validaciones GIIS"},{"name":"Consultas","description":"CRUD de consultas médicas (106 variables GIIS)"},{"name":"Consultas Globales","description":"Búsqueda y filtrado de consultas de todos los pacientes del médico"},{"name":"Citas","description":"Gestión de citas médicas"},{"name":"Antecedentes","description":"Antecedentes clínicos del paciente"},{"name":"Adendums","description":"Notas adicionales (adendums) del expediente del paciente"},{"name":"Documentos Clínicos","description":"Historial de documentos clínicos generados por paciente (consentimientos, altas, avisos, etc.)"},{"name":"Plantillas de Documentos","description":"Plantillas de documentos clínicos personalizadas por médico (consentimientos, avisos, etc.)"},{"name":"Mis Medicamentos","description":"Catálogo personal de medicamentos del médico (cat__medicamento)"},{"name":"KPI","description":"Dashboard de indicadores propios del médico autenticado — pacientes, consultas, citas, CURP, fusiones, tickets, almacenamiento y medicamentos"},{"name":"Sedes","description":"Sedes e instituciones"},{"name":"Manager Auth","description":"Autenticación de managers (plataforma de gestión)"},{"name":"Manager Dashboard","description":"Dashboard y analíticas institucionales"},{"name":"Managers","description":"CRUD de managers"},{"name":"Manager Centros","description":"Gestión de centros de operación (sedes)"},{"name":"Manager Médicos","description":"Gestión de médicos desde la plataforma manager"},{"name":"Manager Institución","description":"Configuración de la institución"},{"name":"Manager Utils","description":"Utilidades (validación CURP, etc.)"},{"name":"CRM Auth","description":"Autenticación admin CRM (god admin)"},{"name":"CRM Dashboard","description":"Stats globales, ingresos, crecimiento"},{"name":"CRM Instituciones","description":"CRUD de instituciones + sub-recursos"},{"name":"CRM Médicos","description":"Listado y gestión global de médicos"},{"name":"CRM Suscripciones","description":"Gestión de suscripciones"},{"name":"CRM Facturas","description":"Historial de facturas"},{"name":"CRM Tickets","description":"Soporte técnico"},{"name":"CRM Cédulas","description":"Validación de cédulas profesionales"},{"name":"CRM Catálogos","description":"Explorar catálogos del sistema"},{"name":"CRM Planes","description":"Configuración de planes de suscripción"},{"name":"CRM Auditoría","description":"Bitácora de actividades"}],"paths":{"/api/pacientes/{id_paciente}/adendums":{"get":{"tags":["Adendums"],"summary":"Listar adendums del paciente","description":"Retorna todos los adendums registrados por el médico autenticado para el paciente, ordenados por fecha descendente.","parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Lista de adendums","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AdendumResponse"}}}}},"401":{"description":"No autorizado"}}},"post":{"tags":["Adendums"],"summary":"Crear adendum","description":"Agrega una nueva nota adicional al expediente del paciente, vinculada al médico autenticado.","parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdendumCreate"}}}},"responses":{"201":{"description":"Adendum creado exitosamente","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Adendum creado"},"id_adendum":{"type":"integer","example":7}}}}}},"400":{"description":"La nota es obligatoria"},"401":{"description":"No autorizado"}}}},"/api/pacientes/{id_paciente}/adendums/{id_adendum}":{"put":{"tags":["Adendums"],"summary":"Actualizar adendum","description":"Edita la nota de un adendum existente. Solo el médico que lo creó puede editarlo.","parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}},{"in":"path","name":"id_adendum","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdendumCreate"}}}},"responses":{"200":{"description":"Adendum actualizado exitosamente","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"La nota es obligatoria"},"401":{"description":"No autorizado"},"404":{"description":"Adendum no encontrado"}}},"delete":{"tags":["Adendums"],"summary":"Eliminar adendum","description":"Elimina un adendum del expediente. Solo el médico que lo creó puede eliminarlo.","parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}},{"in":"path","name":"id_adendum","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Adendum eliminado exitosamente","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"401":{"description":"No autorizado"},"404":{"description":"Adendum no encontrado"}}}},"/api/pacientes/{id_paciente}/alergia-check":{"post":{"tags":["Alergias - Verificación"],"summary":"Verificar si un medicamento puede causar reacción alérgica","description":"Compara el medicamento prescrito contra las alergias registradas del paciente\nusando fuzzy matching inteligente (SOUNDEX, Levenshtein, catálogo de aliases\nfarmacológicos y reacciones cruzadas entre familias).\n\n**Capas de verificación:**\n1. Match directo + fonético (SOUNDEX) + similitud (Levenshtein)\n2. Catálogo de aliases → familias farmacológicas → reacciones cruzadas\n3. Análisis con IA (si ANTHROPIC_API_KEY está configurada)\n\n**Uso recomendado:** Llamar este endpoint ANTES de guardar la prescripción\npara mostrar una advertencia al médico en el frontend.\n","parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"},"description":"ID del paciente"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["medicamento"],"properties":{"medicamento":{"type":"string","description":"Nombre del medicamento a verificar (puede contener errores ortográficos)","example":"penisilina"}}}}}},"responses":{"200":{"description":"Resultado de la verificación","content":{"application/json":{"schema":{"type":"object","properties":{"alerta":{"type":"boolean","description":"true si se detectó posible reacción alérgica","example":true},"mensaje":{"type":"string","description":"Descripción de la alerta o confirmación de seguridad","example":"⚠️ ALERTA: El medicamento \"penisilina\" corresponde a \"penicilina\", al cual el paciente tiene alergia registrada."}}},"examples":{"alerta_directa":{"summary":"Alergia directa detectada","value":{"alerta":true,"mensaje":"⚠️ ALERTA: El medicamento \"penisilina\" corresponde a \"penicilina\", al cual el paciente tiene alergia registrada."}},"alerta_cruzada":{"summary":"Reacción cruzada detectada","value":{"alerta":true,"mensaje":"⚠️ ALERTA (riesgo moderado): El paciente es alérgico a \"penicilina\" (familia: penicilinas). El medicamento \"cefalexina\" (familia: cefalosporinas) puede causar reacción cruzada."}},"sin_alerta":{"summary":"Sin alergias relacionadas","value":{"alerta":false,"mensaje":"No se encontró relación entre el medicamento y las alergias del paciente."}},"sin_alergias":{"summary":"Paciente sin alergias registradas","value":{"alerta":false,"mensaje":"El paciente no tiene alergias registradas."}}}}}},"400":{"description":"Medicamento no proporcionado","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"El campo medicamento es obligatorio"}}}}}},"401":{"description":"No autorizado"}}}},"/api/pacientes/{id_paciente}/antecedentes":{"get":{"tags":["Antecedentes"],"summary":"Listar antecedentes del paciente","parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Lista de antecedentes agrupados por tipo"}}},"post":{"tags":["Antecedentes"],"summary":"Crear antecedente","parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AntecedenteCreate"}}}},"responses":{"201":{"description":"Antecedente creado","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"id_antecedente":{"type":"integer"}}}}}}}}},"/api/pacientes/{id_paciente}/antecedentes/{id_antecedente}":{"put":{"tags":["Antecedentes"],"summary":"Actualizar antecedente","parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}},{"in":"path","name":"id_antecedente","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AntecedenteCreate"}}}},"responses":{"200":{"description":"Antecedente actualizado"},"404":{"description":"Antecedente no encontrado"}}},"delete":{"tags":["Antecedentes"],"summary":"Eliminar antecedente","parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}},{"in":"path","name":"id_antecedente","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Antecedente eliminado"},"404":{"description":"Antecedente no encontrado"}}}},"/api/pacientes/{id_paciente}/archivos/upload-url":{"post":{"tags":["Archivos"],"summary":"Obtener URL firmada para subir archivo a GCS","parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["filename","contentType"],"properties":{"filename":{"type":"string","description":"Nombre original del archivo"},"contentType":{"type":"string","description":"MIME type del archivo (e.g. application/pdf, image/jpeg)"}}}}}},"responses":{"200":{"description":"URL firmada y clave del archivo","content":{"application/json":{"schema":{"type":"object","properties":{"uploadUrl":{"type":"string"},"fileKey":{"type":"string"}}}}}},"400":{"description":"Faltan campos requeridos"}}}},"/api/pacientes/{id_paciente}/archivos":{"post":{"tags":["Archivos"],"summary":"Registrar archivo subido (metadata + thumbnail)","parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["nombre","key","tipo"],"properties":{"nombre":{"type":"string"},"key":{"type":"string","description":"Clave GCS devuelta por upload-url"},"tamano":{"type":"integer"},"tipo":{"type":"string","description":"MIME type del archivo"},"thumbnail":{"type":"string","description":"Thumbnail en base64 (opcional)"}}}}}},"responses":{"201":{"description":"Archivo registrado","content":{"application/json":{"schema":{"type":"object","properties":{"id_archivo":{"type":"integer"}}}}}},"400":{"description":"Faltan campos requeridos"}}},"get":{"tags":["Archivos"],"summary":"Listar archivos del paciente con URLs de descarga","parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Lista de archivos con URLs firmadas","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id_archivo":{"type":"integer"},"nombre":{"type":"string"},"tipo":{"type":"string"},"tamano":{"type":"integer"},"url":{"type":"string"},"thumbnail":{"type":"string"},"fecha":{"type":"string","format":"date-time"}}}}}}}}}},"/api/pacientes/{id_paciente}/archivos/{idArchivo}":{"delete":{"tags":["Archivos"],"summary":"Eliminar archivo (soft delete + borrar de GCS)","parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}},{"in":"path","name":"idArchivo","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Archivo eliminado","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"404":{"description":"Archivo no encontrado"}}}},"/api/auth/login":{"post":{"tags":["Auth"],"summary":"Iniciar sesión","description":"Autentica al médico y retorna access + refresh tokens JWT.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}}},"responses":{"200":{"description":"Login exitoso","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponse"}}}},"401":{"description":"Credenciales inválidas","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/auth/register":{"post":{"tags":["Auth"],"summary":"Registrar médico","description":"Crea un nuevo médico con validaciones GIIS:\n- **CURP** (GIIS#3): Formato RENAPO, genérico para extranjeros, edad 18-90 años\n- **Nombres** (GIIS#4-6): Solo A-Z, Ñ mayúsculas. Especiales: - , . / ' ¨\n- **tipoPersonal** (GIIS#7): 27 valores del catálogo TIPO PERSONAL-SIS\n","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterRequest"}}}},"responses":{"201":{"description":"Médico registrado","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"id_medico":{"type":"integer"}}}}}},"400":{"description":"Errores de validación GIIS","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Duplicado (correo o CURP ya existe)"}}}},"/api/auth/refresh":{"post":{"tags":["Auth"],"summary":"Renovar access token","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshRequest"}}}},"responses":{"200":{"description":"Nuevo access token","content":{"application/json":{"schema":{"type":"object","properties":{"accessToken":{"type":"string"}}}}}},"401":{"description":"Refresh token inválido o expirado"}}}},"/api/auth/me":{"get":{"tags":["Auth"],"summary":"Perfil del médico autenticado","responses":{"200":{"description":"Datos del médico"},"401":{"description":"Token inválido o expirado"}}}},"/api/auth/password":{"patch":{"tags":["Auth"],"summary":"Cambiar contraseña","description":"Actualiza la contraseña del médico autenticado.\nLa nueva contraseña debe cumplir:\n- Mínimo 8 caracteres\n- Al menos una mayúscula, una minúscula, un número y un carácter especial (`@$!%*?&,.-`)\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CambiarPasswordRequest"}}}},"responses":{"200":{"description":"Contraseña actualizada correctamente","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Contraseña actualizada correctamente"}}}}}},"400":{"description":"Campos faltantes o contraseña no cumple requisitos","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Contraseña actual incorrecta o token inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Médico no encontrado"}}}},"/api/pacientes/{id_paciente}/citas/todos":{"get":{"tags":["Citas"],"summary":"Listar citas de todos los médicos de un paciente compartido","description":"Devuelve las citas de TODOS los médicos que atienden al paciente. Solo accesible si el médico autenticado es propietario del paciente o es receptor activo con permiso_agenda=1. Cada cita incluye el campo `es_propia` (1=propia, 0=de otro médico).\n","parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}},{"in":"query","name":"desde","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"hasta","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"status","schema":{"type":"string"}}],"responses":{"200":{"description":"Lista de citas de todos los médicos (con campo es_propia)"},"403":{"description":"Sin acceso a la agenda de este paciente"}}}},"/api/pacientes/{id_paciente}/citas":{"get":{"tags":["Citas"],"summary":"Listar citas PROPIAS del médico para un paciente","description":"Solo devuelve las citas creadas por el médico autenticado (para la vista lista/tab del paciente)","parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}},{"in":"query","name":"desde","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"hasta","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"status","schema":{"type":"string","enum":["pendiente","confirmada","cancelada","completada"]}}],"responses":{"200":{"description":"Lista de citas propias"}}},"post":{"tags":["Citas"],"summary":"Crear cita"}},"/api/citas":{"get":{"tags":["Citas"],"summary":"Listar todas las citas propias del médico (para AgendaPage)","parameters":[{"in":"query","name":"desde","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"hasta","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"status","schema":{"type":"string"}}],"responses":{"200":{"description":"Lista de citas"}}}},"/api/pacientes/{id_paciente}/citas/{id_cita}":{"put":{"tags":["Citas"],"summary":"Actualizar cita (solo el médico creador)"},"delete":{"tags":["Citas"],"summary":"Cancelar cita (solo el médico creador)"}},"/api/pacientes/{id_paciente}/consultas":{"get":{"tags":["Consultas"],"summary":"Listar consultas de un paciente","parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}},{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"Lista paginada de consultas"}}},"post":{"tags":["Consultas"],"summary":"Crear consulta médica","description":"Crea una consulta con las 106 variables GIIS-B015-04-11. Validaciones incluidas:\n\n**Somatometría (GIIS#26-38):** peso, talla, cintura, presión arterial, FC, FR, temperatura, SpO2, glucemia.\n\n**Diagnósticos (GIIS#43-50):** Hasta 3 códigos CIE-10 de 4 caracteres con confirmación diagnóstica.\n\n**Embarazo (GIIS#52-68):** Exclusividad mutua entre pregestacional, embarazo y puerperio.\n\n**Salud del niño (GIIS#77-87):** Condicional a edad <5 o <10 años.\n\n**Gerontología (GIIS#90-96):** Condicional a edad >=60 años.\n\n**Referencia (GIIS#101-102):** Correlación referidoPor / contrarreferido.\n\n**Telemedicina (GIIS#103-106):** Exclusividad telemedicina / teleconsulta.\n\n**primeraVezAnio (GIIS#40):** Se calcula automáticamente.\n\nOpcionalmente incluye prescripciones y órdenes en la misma petición.\n","parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsultaCreate"}}}},"responses":{"201":{"description":"Consulta creada","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"id_consulta":{"type":"integer"}}}}}},"400":{"description":"Errores de validación GIIS","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Paciente no encontrado"}}}},"/api/pacientes/{id_paciente}/consultas/{id_consulta}":{"get":{"tags":["Consultas"],"summary":"Obtener detalle de consulta","description":"Incluye prescripciones, órdenes y paraclínicos asociados.","parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}},{"in":"path","name":"id_consulta","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Detalle completo de la consulta"},"404":{"description":"Consulta no encontrada"}}},"put":{"tags":["Consultas"],"summary":"Actualizar consulta","description":"Actualiza campos de la consulta. Re-valida somatometría si se envían esos campos.","parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}},{"in":"path","name":"id_consulta","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsultaCreate"}}}},"responses":{"200":{"description":"Consulta actualizada"},"400":{"description":"Errores de validación"},"404":{"description":"Consulta no encontrada"}}},"delete":{"tags":["Consultas"],"summary":"Desactivar consulta (soft delete)","parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}},{"in":"path","name":"id_consulta","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Consulta desactivada"},"404":{"description":"Consulta no encontrada"}}}},"/api/consultas":{"get":{"tags":["Consultas"],"summary":"Listar todas las consultas del médico con filtros","parameters":[{"in":"query","name":"paciente","schema":{"type":"string"},"description":"Filtrar por nombre o apellido del paciente"},{"in":"query","name":"id_sede","schema":{"type":"integer"},"description":"Filtrar por consultorio/sede"},{"in":"query","name":"fechaInicio","schema":{"type":"string","format":"date"},"description":"Fecha inicial (YYYY-MM-DD)"},{"in":"query","name":"fechaFin","schema":{"type":"string","format":"date"},"description":"Fecha final (YYYY-MM-DD)"}],"responses":{"200":{"description":"Lista de consultas"}}}},"/api/crm/auth/login":{"post":{"tags":["CRM Auth"],"summary":"Login de admin CRM","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrmLoginRequest"}}}},"responses":{"200":{"description":"Login exitoso","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrmLoginResponse"}}}},"401":{"description":"Credenciales inválidas"}}}},"/api/crm/auth/refresh":{"post":{"tags":["CRM Auth"],"summary":"Renovar access token CRM","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshRequest"}}}},"responses":{"200":{"description":"Token renovado"}}}},"/api/crm/auth/me":{"get":{"tags":["CRM Auth"],"summary":"Perfil del admin CRM autenticado","security":[{"crmBearerAuth":[]}],"responses":{"200":{"description":"Perfil del admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrmAdminProfile"}}}}}}},"/api/crm/auth/logout":{"post":{"tags":["CRM Auth"],"summary":"Cerrar sesión CRM","security":[{"crmBearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"refreshToken":{"type":"string"}}}}}},"responses":{"200":{"description":"Sesión cerrada"}}}},"/api/crm/dashboard/stats":{"get":{"tags":["CRM Dashboard"],"summary":"KPIs globales de la plataforma","security":[{"crmBearerAuth":[]}],"responses":{"200":{"description":"Stats globales","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrmGlobalStats"}}}}}}},"/api/crm/dashboard/revenue":{"get":{"tags":["CRM Dashboard"],"summary":"Ingresos mensuales por suscripciones","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"query","name":"meses","schema":{"type":"integer","default":12},"description":"Meses hacia atrás"}],"responses":{"200":{"description":"Ingresos por mes"}}}},"/api/crm/dashboard/growth":{"get":{"tags":["CRM Dashboard"],"summary":"Crecimiento de médicos nuevos por mes","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"query","name":"meses","schema":{"type":"integer","default":12}}],"responses":{"200":{"description":"Médicos nuevos por mes"}}}},"/api/crm/dashboard/activity":{"get":{"tags":["CRM Dashboard"],"summary":"Actividad reciente (admins + managers)","security":[{"crmBearerAuth":[]}],"responses":{"200":{"description":"Últimas 15 acciones"}}}},"/api/crm/instituciones":{"get":{"tags":["CRM Instituciones"],"summary":"Listar todas las instituciones","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":25}},{"in":"query","name":"buscar","schema":{"type":"string"},"description":"Buscar por nombre, razón social, RFC o correo"},{"in":"query","name":"tipo","schema":{"type":"string","enum":["individual","entidad"]}},{"in":"query","name":"status","schema":{"type":"integer","enum":[0,1,2]}}],"responses":{"200":{"description":"Lista paginada de instituciones","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse"}}}}}},"post":{"tags":["CRM Instituciones"],"summary":"Crear nueva institución","security":[{"crmBearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrmInstitucionCreate"}}}},"responses":{"201":{"description":"Institución creada"}}}},"/api/crm/instituciones/{id}":{"get":{"tags":["CRM Instituciones"],"summary":"Detalle de una institución","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Institución con suscripción y conteos"}}},"put":{"tags":["CRM Instituciones"],"summary":"Actualizar institución","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrmInstitucionUpdate"}}}},"responses":{"200":{"description":"Institución actualizada"}}},"delete":{"tags":["CRM Instituciones"],"summary":"Desactivar institución (solo owner)","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Institución desactivada"}}}},"/api/crm/instituciones/{id}/sedes":{"get":{"tags":["CRM Instituciones"],"summary":"Sedes de una institución","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Lista de sedes con conteos"}}}},"/api/crm/instituciones/{id}/medicos":{"get":{"tags":["CRM Instituciones"],"summary":"Médicos de una institución","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Lista de médicos vinculados"}}}},"/api/crm/instituciones/{id}/suscripcion":{"get":{"tags":["CRM Instituciones"],"summary":"Historial de suscripciones de una institución","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Suscripciones"}}}},"/api/crm/instituciones/{id}/facturas":{"get":{"tags":["CRM Instituciones"],"summary":"Facturas de una institución","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}},{"in":"query","name":"page","schema":{"type":"integer","default":1}}],"responses":{"200":{"description":"Lista paginada de facturas"}}}},"/api/crm/instituciones/{id}/uso":{"get":{"tags":["CRM Instituciones"],"summary":"Consumo de registros mensual","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}},{"in":"query","name":"meses","schema":{"type":"integer","default":12}}],"responses":{"200":{"description":"Uso mensual por sede"}}}},"/api/crm/medicos":{"get":{"tags":["CRM Médicos"],"summary":"Listar todos los médicos de la plataforma","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":25}},{"in":"query","name":"buscar","schema":{"type":"string"}},{"in":"query","name":"tipo_usuario","schema":{"type":"string","enum":["ENTITY","INDIVIDUAL"]}},{"in":"query","name":"cedula_status","schema":{"type":"integer","enum":[0,1,2,3]},"description":"0=Sin verificar, 1=Pendiente, 2=Verificado, 3=Rechazado"},{"in":"query","name":"status","schema":{"type":"integer","enum":[0,1]}}],"responses":{"200":{"description":"Lista paginada"}}}},"/api/crm/medicos/{id}":{"get":{"tags":["CRM Médicos"],"summary":"Detalle de un médico","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Médico con sedes y conteos"}}},"put":{"tags":["CRM Médicos"],"summary":"Actualizar médico (status, cédula)","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer","enum":[0,1]},"cedula_p_status":{"type":"integer","enum":[0,1,2,3]},"cedula_e_status":{"type":"integer","enum":[0,1,2,3]},"tipo_usuario":{"type":"string","enum":["ENTITY","INDIVIDUAL"]}}}}}},"responses":{"200":{"description":"Médico actualizado"}}}},"/api/crm/suscripciones":{"get":{"tags":["CRM Suscripciones"],"summary":"Listar todas las suscripciones","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"query","name":"status","schema":{"type":"string","enum":["trial","active","past_due","cancelled","suspended"]}}],"responses":{"200":{"description":"Lista de suscripciones"}}}},"/api/crm/suscripciones/{id}":{"put":{"tags":["CRM Suscripciones"],"summary":"Actualizar suscripción","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"id_plan":{"type":"integer"},"periodo":{"type":"string","enum":["mensual","anual"]},"status":{"type":"string","enum":["trial","active","past_due","cancelled","suspended"]},"fecha_proximo_cobro":{"type":"string","format":"date"},"trial_end":{"type":"string","format":"date"}}}}}},"responses":{"200":{"description":"Suscripción actualizada"}}}},"/api/crm/suscripciones/{id}/cancel":{"post":{"tags":["CRM Suscripciones"],"summary":"Cancelar suscripción (solo owner)","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Suscripción cancelada"}}}},"/api/crm/facturas":{"get":{"tags":["CRM Facturas"],"summary":"Listar todas las facturas","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"query","name":"status","schema":{"type":"string","enum":["draft","pending","paid","failed","refunded"]}},{"in":"query","name":"page","schema":{"type":"integer","default":1}}],"responses":{"200":{"description":"Lista paginada de facturas"}}}},"/api/crm/tickets":{"get":{"tags":["CRM Tickets"],"summary":"Listar tickets de soporte","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"query","name":"status","schema":{"type":"integer","enum":[0,1,2,3]},"description":"0=Abierto, 1=En progreso, 2=Resuelto, 3=Cerrado"},{"in":"query","name":"prioridad","schema":{"type":"string","enum":["critica","alta","media","baja"]}}],"responses":{"200":{"description":"Lista de tickets"}}}},"/api/crm/tickets/{id}":{"get":{"tags":["CRM Tickets"],"summary":"Detalle de ticket con comentarios y archivos","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Ticket completo"}}}},"/api/crm/tickets/{id}/reply":{"post":{"tags":["CRM Tickets"],"summary":"Responder a un ticket","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrmTicketReply"}}}},"responses":{"200":{"description":"Respuesta enviada"}}}},"/api/crm/tickets/{id}/close":{"post":{"tags":["CRM Tickets"],"summary":"Cerrar ticket","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Ticket cerrado"}}}},"/api/crm/cedulas/pending":{"get":{"tags":["CRM Cédulas"],"summary":"Cédulas profesionales pendientes de validar","security":[{"crmBearerAuth":[]}],"responses":{"200":{"description":"Lista de médicos con cédula pendiente"}}}},"/api/crm/cedulas/{id}/approve":{"post":{"tags":["CRM Cédulas"],"summary":"Aprobar cédula","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"},"description":"id_medico"},{"in":"query","name":"tipo","schema":{"type":"string","enum":["profesional","especialidad"]},"description":"Tipo de cédula a aprobar (default profesional)"}],"responses":{"200":{"description":"Cédula aprobada"}}}},"/api/crm/cedulas/{id}/reject":{"post":{"tags":["CRM Cédulas"],"summary":"Rechazar cédula","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}},{"in":"query","name":"tipo","schema":{"type":"string","enum":["profesional","especialidad"]}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrmCedulaReject"}}}},"responses":{"200":{"description":"Cédula rechazada"}}}},"/api/crm/catalogos":{"get":{"tags":["CRM Catálogos"],"summary":"Listar todos los catálogos del sistema","security":[{"crmBearerAuth":[]}],"responses":{"200":{"description":"Lista de tablas cat__* con conteo aproximado"}}}},"/api/crm/catalogos/stats":{"get":{"tags":["CRM Catálogos"],"summary":"Estadísticas de catálogos (conteos y tamaño)","security":[{"crmBearerAuth":[]}],"responses":{"200":{"description":"Stats por tabla"}}}},"/api/crm/catalogos/{cat}":{"get":{"tags":["CRM Catálogos"],"summary":"Explorar un catálogo específico","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"path","name":"cat","required":true,"schema":{"type":"string"},"description":"Nombre de la tabla (ej: cat__cie, cat__clues, cat__c_postal)"},{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":50}},{"in":"query","name":"buscar","schema":{"type":"string"}}],"responses":{"200":{"description":"Registros del catálogo con columnas"}}}},"/api/crm/planes":{"get":{"tags":["CRM Planes"],"summary":"Listar planes de suscripción","security":[{"crmBearerAuth":[]}],"responses":{"200":{"description":"Todos los planes"}}},"post":{"tags":["CRM Planes"],"summary":"Crear nuevo plan (solo owner)","security":[{"crmBearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrmPlanCreate"}}}},"responses":{"201":{"description":"Plan creado"}}}},"/api/crm/planes/{id}":{"get":{"tags":["CRM Planes"],"summary":"Detalle de un plan con suscripciones activas","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Plan con conteo de suscripciones"}}},"put":{"tags":["CRM Planes"],"summary":"Actualizar plan (solo owner)","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrmPlanCreate"}}}},"responses":{"200":{"description":"Plan actualizado"}}}},"/api/crm/auditoria/admin":{"get":{"tags":["CRM Auditoría"],"summary":"Bitácora de acciones de admins CRM","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":50}},{"in":"query","name":"accion","schema":{"type":"string"},"description":"Filtrar por tipo de acción"}],"responses":{"200":{"description":"Log de acciones admin"}}}},"/api/crm/auditoria/medicos":{"get":{"tags":["CRM Auditoría"],"summary":"Bitácora de acciones de médicos","security":[{"crmBearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":50}},{"in":"query","name":"id_medico","schema":{"type":"integer"},"description":"Filtrar por médico específico"}],"responses":{"200":{"description":"Log de acciones médicos"}}}},"/api/documentos/config":{"get":{"tags":["Plantillas de Documentos"],"summary":"Listar plantillas del médico","description":"Retorna todas las plantillas de documentos clínicos configuradas por el médico autenticado. Si no existe fila para un tipo, se usa el texto default del sistema.\n","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Lista de plantillas","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DocumentoConfigResponse"}}}}},"401":{"description":"No autorizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Plantillas de Documentos"],"summary":"Crear plantilla de documento clínico","description":"Crea una nueva plantilla personalizada para el médico autenticado. El campo `texto` soporta las variables: `{{NOMBRE_PACIENTE}}`, `{{MEDICO}}`, `{{FECHA}}`, `{{ESPECIALIDAD}}`.\n","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentoConfigCreate"}}}},"responses":{"201":{"description":"Plantilla creada exitosamente","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Plantilla creada"},"id_config":{"type":"integer","example":3}}}}}},"400":{"description":"Datos inválidos","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No autorizado"}}}},"/api/documentos/config/{id_config}":{"get":{"tags":["Plantillas de Documentos"],"summary":"Obtener una plantilla por ID","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id_config","required":true,"schema":{"type":"integer"},"description":"ID de la plantilla"}],"responses":{"200":{"description":"Plantilla encontrada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentoConfigResponse"}}}},"401":{"description":"No autorizado"},"404":{"description":"Plantilla no encontrada"}}},"put":{"tags":["Plantillas de Documentos"],"summary":"Actualizar plantilla","description":"Edita una plantilla existente del médico autenticado. Solo se actualizan los campos enviados.","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id_config","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentoConfigUpdate"}}}},"responses":{"200":{"description":"Plantilla actualizada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"Datos inválidos"},"401":{"description":"No autorizado"},"404":{"description":"Plantilla no encontrada"}}},"delete":{"tags":["Plantillas de Documentos"],"summary":"Eliminar plantilla","description":"Elimina permanentemente una plantilla del médico autenticado.","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id_config","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Plantilla eliminada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"401":{"description":"No autorizado"},"404":{"description":"Plantilla no encontrada"}}}},"/api/documentos/config/generar-texto":{"post":{"tags":["Plantillas de Documentos"],"summary":"Generar texto de plantilla con IA","description":"Usa OpenAI para generar automáticamente el texto de un consentimiento informado basándose en el título y tipo de plantilla. El texto generado incluye únicamente las variables `{{NOMBRE_PACIENTE}}`, `{{FECHA}}` y `{{MEDICO}}`.\n","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["titulo","tipo"],"properties":{"titulo":{"type":"string","example":"Consentimiento para cirugía de cataratas"},"tipo":{"type":"string","enum":["consentimiento_informado","consentimiento_cirugia","consentimiento_anestesia","consentimiento_procedimiento","aviso_privacidad","alta_voluntaria","rechazo_tratamiento","otro"],"example":"consentimiento_cirugia"}}}}}},"responses":{"200":{"description":"Texto generado exitosamente","content":{"application/json":{"schema":{"type":"object","properties":{"texto":{"type":"string","description":"Texto del consentimiento generado por IA"}}}}}},"400":{"description":"Título o tipo faltante/inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No autorizado"},"429":{"description":"Límite de OpenAI alcanzado"},"500":{"description":"Error de configuración o de generación"}}}},"/api/documentos/config/{id_config}/toggle":{"patch":{"tags":["Plantillas de Documentos"],"summary":"Activar / desactivar plantilla","description":"Alterna el estado `activo` de la plantilla (0↔1).","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id_config","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Estado cambiado correctamente","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Plantilla activada"},"activo":{"type":"integer","enum":[0,1],"example":1}}}}}},"401":{"description":"No autorizado"},"404":{"description":"Plantilla no encontrada"}}}},"/api/fusion/sugerencias":{"get":{"tags":["Fusión de Pacientes"],"summary":"Sugerencias de fusión","description":"Detecta pares de pacientes con alta similitud donde uno tiene CURP genérica\ny otro tiene CURP real. Compara nombre, apellidos, fecha de nacimiento.\n","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":20}},{"in":"query","name":"q","schema":{"type":"string"},"description":"Buscar por nombre del paciente"}],"responses":{"200":{"description":"Lista paginada de sugerencias de fusión"}}}},"/api/fusion/solicitud":{"post":{"tags":["Fusión de Pacientes"],"summary":"Crear solicitud de fusión","description":"Crea una solicitud para fusionar dos pacientes. El paciente origen (CURP genérica)\nserá eliminado y sus registros migrados al paciente destino (CURP real).\n","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id_paciente_solicitado","id_paciente_fusionado"],"properties":{"id_paciente_solicitado":{"type":"integer","description":"ID del paciente con CURP genérica (origen, será eliminado)"},"id_paciente_fusionado":{"type":"integer","description":"ID del paciente con CURP real (destino, se conserva)"},"comentario_medico":{"type":"string"}}}}}},"responses":{"201":{"description":"Solicitud creada"},"400":{"description":"Validación fallida"},"409":{"description":"Ya existe solicitud pendiente"}}}},"/api/fusion/mis-solicitudes":{"get":{"tags":["Fusión de Pacientes"],"summary":"Historial de solicitudes del médico","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":20}},{"in":"query","name":"status","schema":{"type":"integer","enum":[0,1,2]},"description":"0=pendiente, 1=aprobada, 2=rechazada"}],"responses":{"200":{"description":"Lista paginada de solicitudes"}}}},"/api/fusion/pendientes/count":{"get":{"tags":["Fusión de Pacientes"],"summary":"Conteo de solicitudes pendientes y nuevas resueltas","description":"Para mostrar badge en sidebar del médico","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Conteo de pendientes y nuevas resueltas"}}}},"/api/kpi/resumen":{"get":{"tags":["KPI"],"summary":"Resumen general del médico — pacientes, consultas y citas","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Totales propios del médico autenticado"}}}},"/api/kpi/citas-semana":{"get":{"tags":["KPI"],"summary":"Citas por día en los últimos 7 días (gráfica semanal)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Array con citas agrupadas por día"}}}},"/api/kpi/curp":{"get":{"tags":["KPI"],"summary":"Pacientes con CURP real vs CURP genérica","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Conteo con_curp / sin_curp"}}}},"/api/kpi/fusiones":{"get":{"tags":["KPI"],"summary":"Fusiones de pacientes solicitadas por el médico","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Completadas, pendientes y rechazadas"}}}},"/api/kpi/tickets":{"get":{"tags":["KPI"],"summary":"Tickets de soporte del médico","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Abiertos, en proceso y cerrados"}}}},"/api/kpi/almacenamiento":{"get":{"tags":["KPI"],"summary":"Archivos y espacio usado en expedientes del médico","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"total_archivos, bytes_usados, mb_usados"}}}},"/api/kpi/medicamentos":{"get":{"tags":["KPI"],"summary":"Total de medicamentos propios en catálogo","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"total_medicamentos"}}}},"/api/log/admin/medicos":{"get":{"tags":["Bitácora - Admin"],"summary":"Consultar logs de médicos","description":"Permite al admin CRM consultar toda la bitácora de médicos. Soporta filtros por id_medico, id_sede, tipo_operacion, entidad, buscar (texto libre), fecha_inicio y fecha_fin.\n","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":20,"maximum":100}},{"in":"query","name":"id_medico","schema":{"type":"integer"}},{"in":"query","name":"id_sede","schema":{"type":"integer"}},{"in":"query","name":"tipo_operacion","schema":{"type":"string","enum":["CREATE","READ","UPDATE","DELETE","AUTH","NAVIGATION","ACTION"]}},{"in":"query","name":"entidad","schema":{"type":"string"}},{"in":"query","name":"buscar","schema":{"type":"string"}},{"in":"query","name":"fecha_inicio","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"fecha_fin","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Lista paginada de logs de médicos"}}}},"/api/log/admin/managers":{"get":{"tags":["Bitácora - Admin"],"summary":"Consultar logs de managers","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":20,"maximum":100}},{"in":"query","name":"id_manager","schema":{"type":"integer"}},{"in":"query","name":"id_institucion","schema":{"type":"integer"}},{"in":"query","name":"id_sede","schema":{"type":"integer"}},{"in":"query","name":"tipo_operacion","schema":{"type":"string","enum":["CREATE","READ","UPDATE","DELETE","AUTH","NAVIGATION","ACTION"]}},{"in":"query","name":"buscar","schema":{"type":"string"}},{"in":"query","name":"fecha_inicio","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"fecha_fin","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Lista paginada de logs de managers"}}}},"/api/log/admin/admins":{"get":{"tags":["Bitácora - Admin"],"summary":"Consultar logs de admins CRM","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":20,"maximum":100}},{"in":"query","name":"id_admin","schema":{"type":"integer"}},{"in":"query","name":"tipo_operacion","schema":{"type":"string","enum":["CREATE","READ","UPDATE","DELETE","AUTH","NAVIGATION","ACTION"]}},{"in":"query","name":"buscar","schema":{"type":"string"}},{"in":"query","name":"fecha_inicio","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"fecha_fin","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Lista paginada de logs de admins"}}}},"/api/log/admin/stats":{"get":{"tags":["Bitácora - Admin"],"summary":"Estadísticas generales de actividad","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"fecha_inicio","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"fecha_fin","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Totales y top eventos"}}}},"/api/log/manager/medicos":{"get":{"tags":["Bitácora - Manager"],"summary":"Consultar logs de médicos de sus sedes","description":"Managers ven solo logs de médicos en sedes a las que tienen acceso. Superadmin de la institución ve todas las sedes.\n","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":20,"maximum":100}},{"in":"query","name":"id_medico","schema":{"type":"integer"}},{"in":"query","name":"tipo_operacion","schema":{"type":"string","enum":["CREATE","READ","UPDATE","DELETE","AUTH","NAVIGATION","ACTION"]}},{"in":"query","name":"buscar","schema":{"type":"string"}},{"in":"query","name":"fecha_inicio","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"fecha_fin","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Lista paginada de logs de médicos"}}}},"/api/log/manager/managers":{"get":{"tags":["Bitácora - Manager"],"summary":"Consultar logs de managers de la misma institución","security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":20,"maximum":100}},{"in":"query","name":"id_manager","schema":{"type":"integer"}},{"in":"query","name":"tipo_operacion","schema":{"type":"string","enum":["CREATE","READ","UPDATE","DELETE","AUTH","NAVIGATION","ACTION"]}},{"in":"query","name":"buscar","schema":{"type":"string"}},{"in":"query","name":"fecha_inicio","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"fecha_fin","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Lista paginada de logs de managers"}}}},"/api/log/track":{"post":{"tags":["Bitácora - Tracker"],"summary":"Registrar evento individual (tipo Google Analytics)","description":"Endpoint comodín para registrar eventos desde el frontend. Acepta auth de cualquier tier (médico, manager, admin).\n","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"evento":{"type":"string","description":"Nombre del evento (ej. \"imprimir_receta\", \"ver_expediente\")"},"descripcion":{"type":"string","description":"Descripción legible"},"entidad":{"type":"string"},"entidad_id":{"type":"integer"},"detalle":{"type":"object","description":"Datos adicionales del evento"}}}}}},"responses":{"200":{"description":"Evento registrado"}}}},"/api/log/track/batch":{"post":{"tags":["Bitácora - Tracker"],"summary":"Registrar batch de eventos (máximo 50)","description":"Envía múltiples eventos en una sola petición. Útil para frontends que acumulan eventos y los envían periódicamente.\n","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"eventos":{"type":"array","maxItems":50,"items":{"type":"object","properties":{"evento":{"type":"string"},"descripcion":{"type":"string"},"tipo":{"type":"string","enum":["CREATE","READ","UPDATE","DELETE","AUTH","NAVIGATION","ACTION"]},"entidad":{"type":"string"},"entidad_id":{"type":"integer"},"detalle":{"type":"object"}}}}}}}}},"responses":{"200":{"description":"Eventos registrados"}}}},"/api/log/evento":{"post":{"tags":["Bitácora - Tracker"],"summary":"Registrar evento detallado manualmente","description":"Para uso desde controllers o frontend cuando se necesita registrar un evento CRUD con todos los detalles (valores originales, nuevos, recovery).\n","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["tipo_operacion","descripcion"],"properties":{"tipo_operacion":{"type":"string","enum":["CREATE","READ","UPDATE","DELETE","AUTH","NAVIGATION","ACTION"]},"entidad":{"type":"string"},"entidad_id":{"type":"integer"},"descripcion":{"type":"string"},"detalle":{"type":"object"},"to_id_medico":{"type":"integer"},"to_id_manager":{"type":"integer"},"id_institucion":{"type":"integer"},"id_sede":{"type":"integer"}}}}}},"responses":{"200":{"description":"Evento registrado"}}}},"/api/manager/auth/login":{"post":{"tags":["Manager Auth"],"summary":"Login de manager","description":"Autentica al manager y retorna access + refresh tokens JWT. Incluye centros asignados.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagerLoginRequest"}}}},"responses":{"200":{"description":"Login exitoso","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagerLoginResponse"}}}},"400":{"description":"Campos obligatorios faltantes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Credenciales inválidas","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/manager/auth/refresh":{"post":{"tags":["Manager Auth"],"summary":"Renovar access token de manager","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshRequest"}}}},"responses":{"200":{"description":"Nuevo access token","content":{"application/json":{"schema":{"type":"object","properties":{"accessToken":{"type":"string"}}}}}},"400":{"description":"refreshToken requerido"},"401":{"description":"Token inválido, expirado o sesión revocada"}}}},"/api/manager/auth/register-institution":{"post":{"tags":["Manager Auth"],"summary":"Registrar institución y primer superadmin","description":"Endpoint público que crea una institución nueva junto con el primer manager (superadmin).\nIncluye suscripción trial de 30 días (plan Starter) y notificación de bienvenida.\nRetorna tokens JWT para inicio de sesión inmediato.\n","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagerRegisterInstitutionRequest"}}}},"responses":{"201":{"description":"Institución y manager creados","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Institución y manager creados exitosamente"},"accessToken":{"type":"string"},"refreshToken":{"type":"string"},"manager":{"type":"object","properties":{"id_manager":{"type":"integer"},"nombre":{"type":"string"},"apellido_paterno":{"type":"string"},"correo":{"type":"string"},"rol":{"type":"string","example":"superadmin"},"id_institucion":{"type":"integer"},"institucion_nombre":{"type":"string"},"centros":{"type":"array","items":{"type":"object"}}}}}}}}},"400":{"description":"Campos obligatorios faltantes o contraseña corta","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Ya existe una cuenta con ese correo"}}}},"/api/manager/auth/me":{"get":{"tags":["Manager Auth"],"summary":"Perfil del manager autenticado","description":"Retorna datos del manager, centros asignados e info de suscripción.","security":[{"managerBearerAuth":[]}],"responses":{"200":{"description":"Datos del manager con centros y suscripción"},"401":{"description":"Token inválido o expirado"},"404":{"description":"Manager no encontrado"}}}},"/api/manager/auth/logout":{"post":{"tags":["Manager Auth"],"summary":"Cerrar sesión (revocar refresh token)","security":[{"managerBearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"refreshToken":{"type":"string","description":"Refresh token a revocar"}}}}}},"responses":{"200":{"description":"Sesión cerrada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}}}}},"/api/manager/dashboard/summary":{"get":{"tags":["Manager Dashboard"],"summary":"Resumen del dashboard","description":"Retorna métricas clave — médicos activos, centros, consultas del mes y total de pacientes.","security":[{"managerBearerAuth":[]}],"responses":{"200":{"description":"Métricas del dashboard","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardSummary"}}}}}}},"/api/manager/dashboard/usage":{"get":{"tags":["Manager Dashboard"],"summary":"Uso mensual histórico","description":"Retorna consultas, pacientes nuevos y citas agrupados por mes.","security":[{"managerBearerAuth":[]}],"parameters":[{"in":"query","name":"meses","schema":{"type":"integer","default":6},"description":"Cantidad de meses hacia atrás"}],"responses":{"200":{"description":"Datos de uso mensual","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardUsage"}}}}}}},"/api/manager/managers":{"get":{"tags":["Managers"],"summary":"Listar managers de la institución","description":"Requiere rol superadmin o admin. Paginado con búsqueda y filtros.","security":[{"managerBearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":20}},{"in":"query","name":"buscar","schema":{"type":"string"},"description":"Buscar por nombre, apellido o correo"},{"in":"query","name":"rol","schema":{"type":"string","enum":["superadmin","admin","viewer"]}},{"in":"query","name":"status","schema":{"type":"integer","enum":[0,1]}}],"responses":{"200":{"description":"Lista paginada de managers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse"}}}},"403":{"description":"Permisos insuficientes"}}},"post":{"tags":["Managers"],"summary":"Crear manager","description":"Requiere rol superadmin o admin. Solo superadmin puede crear otro superadmin.\nOpcionalmente asigna centros con permisos específicos.\n","security":[{"managerBearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagerRegisterRequest"}}}},"responses":{"201":{"description":"Manager registrado","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"id_manager":{"type":"integer"}}}}}},"400":{"description":"Campos obligatorios faltantes o rol inválido"},"403":{"description":"Permisos insuficientes"},"409":{"description":"Correo duplicado"}}}},"/api/manager/managers/{id}":{"get":{"tags":["Managers"],"summary":"Obtener manager por ID","description":"Requiere rol superadmin o admin. Incluye centros asignados con permisos.","security":[{"managerBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Datos del manager con centros"},"403":{"description":"Permisos insuficientes"},"404":{"description":"Manager no encontrado"}}},"put":{"tags":["Managers"],"summary":"Actualizar manager","description":"Requiere rol superadmin o admin. Solo superadmin puede cambiar roles.\nNo puedes desactivarte a ti mismo. Opcionalmente reasigna centros.\n","security":[{"managerBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagerUpdateRequest"}}}},"responses":{"200":{"description":"Manager actualizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"No hay campos para actualizar o auto-desactivación"},"403":{"description":"Solo superadmin puede cambiar roles"},"404":{"description":"Manager no encontrado"}}},"delete":{"tags":["Managers"],"summary":"Desactivar manager (soft delete)","description":"Solo superadmin. Revoca todas las sesiones activas. No puedes desactivarte a ti mismo.","security":[{"managerBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Manager desactivado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"No puedes desactivarte a ti mismo"},"403":{"description":"Solo superadmin"},"404":{"description":"Manager no encontrado"}}}},"/api/manager/centros":{"get":{"tags":["Manager Centros"],"summary":"Listar centros accesibles","description":"Retorna los centros (sedes) a los que el manager tiene acceso. Incluye conteo de médicos y pacientes.","security":[{"managerBearerAuth":[]}],"responses":{"200":{"description":"Lista de centros con estadísticas"}}},"post":{"tags":["Manager Centros"],"summary":"Crear centro","description":"Requiere rol superadmin o admin. Valida límite de sedes según plan.\nSi se proporciona CLUES, debe ser de 11 caracteres.\n","security":[{"managerBearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagerCentroCreate"}}}},"responses":{"201":{"description":"Centro creado","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"id_sede":{"type":"integer"}}}}}},"400":{"description":"CLUES inválida"},"403":{"description":"Límite de centros alcanzado o permisos insuficientes"}}}},"/api/manager/centros/{id}":{"get":{"tags":["Manager Centros"],"summary":"Obtener centro por ID","description":"Incluye lista de médicos vinculados al centro.","security":[{"managerBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Datos del centro con médicos"},"404":{"description":"Centro no encontrado"}}},"put":{"tags":["Manager Centros"],"summary":"Actualizar centro","description":"Requiere rol superadmin o admin.","security":[{"managerBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagerCentroCreate"}}}},"responses":{"200":{"description":"Centro actualizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"CLUES inválida"},"403":{"description":"Permisos insuficientes"},"404":{"description":"Centro no encontrado"}}},"delete":{"tags":["Manager Centros"],"summary":"Desactivar centro (soft delete)","description":"Solo superadmin.","security":[{"managerBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Centro desactivado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"403":{"description":"Solo superadmin"},"404":{"description":"Centro no encontrado"}}}},"/api/manager/medicos":{"get":{"tags":["Manager Médicos"],"summary":"Listar médicos de la institución","description":"Lista médicos vinculados a los centros accesibles. Paginado con búsqueda y filtros.","security":[{"managerBearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":20}},{"in":"query","name":"buscar","schema":{"type":"string"},"description":"Buscar por nombre, apellido, correo o CURP"},{"in":"query","name":"id_sede","schema":{"type":"integer"},"description":"Filtrar por centro específico"},{"in":"query","name":"status","schema":{"type":"integer","enum":[0,1]}}],"responses":{"200":{"description":"Lista paginada de médicos","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse"}}}}}},"post":{"tags":["Manager Médicos"],"summary":"Crear médico desde manager","description":"Requiere rol superadmin o admin. Aplica validaciones GIIS para nombre, CURP y tipo de personal.\nVincula automáticamente al médico con la sede indicada.\n","security":[{"managerBearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagerMedicoCreate"}}}},"responses":{"201":{"description":"Médico registrado","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"id_medico":{"type":"integer"}}}}}},"400":{"description":"Errores de validación GIIS o campos faltantes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Permisos insuficientes"},"409":{"description":"Correo o CURP duplicado"}}}},"/api/manager/medicos/{id}":{"get":{"tags":["Manager Médicos"],"summary":"Obtener médico por ID","description":"Incluye estadísticas básicas (total consultas y pacientes).","security":[{"managerBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Datos del médico con estadísticas"},"404":{"description":"Médico no encontrado"}}},"put":{"tags":["Manager Médicos"],"summary":"Actualizar datos de un médico","description":"Requiere rol superadmin o admin. Solo enviar los campos que cambian.","security":[{"managerBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"nombre":{"type":"string"},"apellido_paterno":{"type":"string"},"apellido_materno":{"type":"string"},"correo":{"type":"string"},"telefono":{"type":"string"},"id_especialidad":{"type":"integer"},"cedula":{"type":"string"},"tipo_usuario":{"type":"string"},"status":{"type":"integer","enum":[0,1]}}}}}},"responses":{"200":{"description":"Médico actualizado"},"400":{"description":"Datos inválidos"},"404":{"description":"Médico no encontrado"}}},"delete":{"tags":["Manager Médicos"],"summary":"Desactivar médico (soft delete)","description":"Requiere rol superadmin o admin. El médico debe pertenecer a la institución.","security":[{"managerBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Médico desactivado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"403":{"description":"Permisos insuficientes"},"404":{"description":"Médico no encontrado"}}}},"/api/manager/medicos/{id}/stats":{"get":{"tags":["Manager Médicos"],"summary":"Estadísticas detalladas del médico","description":"Retorna conteos, consultas por mes, pacientes por mes, estimación de espacio\nen almacenamiento y última actividad.\n","security":[{"managerBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Estadísticas detalladas","content":{"application/json":{"schema":{"type":"object","properties":{"medico":{"type":"object"},"counts":{"type":"object","properties":{"total_pacientes":{"type":"integer"},"total_consultas":{"type":"integer"},"total_citas":{"type":"integer"},"total_antecedentes":{"type":"integer"}}},"consultasMes":{"type":"array","items":{"type":"object","properties":{"anio":{"type":"integer"},"mes":{"type":"integer"},"total":{"type":"integer"}}}},"pacientesMes":{"type":"array","items":{"type":"object","properties":{"anio":{"type":"integer"},"mes":{"type":"integer"},"total":{"type":"integer"}}}},"espacio":{"type":"object","properties":{"total_registros":{"type":"integer"},"total_bytes":{"type":"integer"}}},"ultimaActividad":{"type":"string","format":"date-time","nullable":true}}}}}},"404":{"description":"Médico no encontrado"}}}},"/api/manager/medicos/{id}/sedes":{"get":{"tags":["Manager Médicos"],"summary":"Listar sedes/centros asignados a un médico","description":"Retorna las sedes activas vinculadas al médico con rol y permisos.","security":[{"managerBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Lista de sedes asignadas","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id_sede_medico":{"type":"integer"},"id_sede":{"type":"integer"},"nombre":{"type":"string"},"clave":{"type":"string"},"rol":{"type":"string","enum":["titular","asociado","temporal","administrativo"]},"puede_compartir":{"type":"integer"},"puede_agendar":{"type":"integer"},"puede_consultar":{"type":"integer"},"status":{"type":"integer"},"fecha_inicio":{"type":"string","format":"date"},"fecha":{"type":"string","format":"date-time"}}}}}}}}},"404":{"description":"Médico no encontrado"}}},"post":{"tags":["Manager Médicos"],"summary":"Asignar un centro/sede a un médico","description":"Requiere rol superadmin o admin. Valida que la sede pertenezca a la misma institución.\nSi existía un registro inactivo, lo reactiva en vez de crear uno nuevo.\n","security":[{"managerBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id_sede","rol"],"properties":{"id_sede":{"type":"integer"},"rol":{"type":"string","enum":["titular","asociado","temporal","administrativo"]}}}}}},"responses":{"201":{"description":"Centro asignado correctamente"},"400":{"description":"Selecciona un centro o rol inválido"},"404":{"description":"Médico o sede no encontrada"},"409":{"description":"Este centro ya está asignado al médico"}}}},"/api/manager/medicos/{id}/sedes/{idSede}":{"delete":{"tags":["Manager Médicos"],"summary":"Desasignar un centro/sede de un médico","description":"Soft delete — marca status=0 y fecha_fin=hoy. Requiere rol superadmin o admin.","security":[{"managerBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"},"description":"id_medico"},{"in":"path","name":"idSede","required":true,"schema":{"type":"integer"},"description":"id_sede a desasignar"}],"responses":{"200":{"description":"Centro desasignado correctamente"},"404":{"description":"Asignación no encontrada"}}}},"/api/manager/medicos/{id}/password":{"patch":{"tags":["Manager Médicos"],"summary":"Resetear contraseña de un médico","description":"Permite al manager establecer una nueva contraseña para el médico sin requerir la contraseña actual. Requiere rol superadmin o admin.","security":[{"managerBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"},"description":"id_medico"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["nuevaPassword"],"properties":{"nuevaPassword":{"type":"string","minLength":8}}}}}},"responses":{"200":{"description":"Contraseña actualizada correctamente"},"400":{"description":"nuevaPassword faltante o muy corta"},"404":{"description":"Médico no encontrado"}}}},"/api/manager/institucion":{"get":{"tags":["Manager Institución"],"summary":"Obtener datos de la institución","security":[{"managerBearerAuth":[]}],"responses":{"200":{"description":"Datos de la institución"},"404":{"description":"Institución no encontrada"}}},"put":{"tags":["Manager Institución"],"summary":"Actualizar institución","description":"Solo superadmin. Campos editables — nombre, razón social, RFC, logo, contacto, compartir pacientes.","security":[{"managerBearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstitucionUpdate"}}}},"responses":{"200":{"description":"Institución actualizada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"No hay campos para actualizar"},"403":{"description":"Solo superadmin"}}}},"/api/manager/fusion/pendientes/count":{"get":{"tags":["Manager Fusión"],"summary":"Conteo de solicitudes de fusión pendientes","description":"Para mostrar badge en sidebar del manager","security":[{"managerBearerAuth":[]}],"responses":{"200":{"description":"Conteo de pendientes","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"count":{"type":"integer"}}}}}}}}},"/api/manager/fusion/solicitudes":{"get":{"tags":["Manager Fusión"],"summary":"Listar solicitudes de fusión","description":"Lista todas las solicitudes de fusión de la institución del manager.","security":[{"managerBearerAuth":[]}],"parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1}},{"in":"query","name":"limit","schema":{"type":"integer","default":20}},{"in":"query","name":"status","schema":{"type":"integer","enum":[0,1,2]},"description":"0=pendiente, 1=aprobada, 2=rechazada"},{"in":"query","name":"q","schema":{"type":"string"},"description":"Buscar por nombre de paciente o médico"}],"responses":{"200":{"description":"Lista paginada de solicitudes"}}}},"/api/manager/fusion/solicitudes/{id}":{"get":{"tags":["Manager Fusión"],"summary":"Detalle de solicitud con impacto","description":"Muestra información detallada de la solicitud incluyendo datos de ambos pacientes\ny conteo de registros que serán migrados.\n","security":[{"managerBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Detalle de solicitud con impacto"},"403":{"description":"Sin acceso a la sede"},"404":{"description":"Solicitud no encontrada"}}}},"/api/manager/fusion/solicitudes/{id}/aprobar":{"put":{"tags":["Manager Fusión"],"summary":"Aprobar solicitud y ejecutar fusión","description":"Aprueba la solicitud y ejecuta el proceso completo de fusión:\nmigración de registros hijos, movimiento de archivos en GCP,\ny desactivación del paciente origen.\n","security":[{"managerBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"comentario_admin":{"type":"string"}}}}}},"responses":{"200":{"description":"Fusión completada"},"400":{"description":"Solicitud ya procesada o pacientes inválidos"},"403":{"description":"Sin acceso a la sede"},"404":{"description":"Solicitud no encontrada"}}}},"/api/manager/fusion/solicitudes/{id}/rechazar":{"put":{"tags":["Manager Fusión"],"summary":"Rechazar solicitud de fusión","description":"Rechaza la solicitud. El comentario de rechazo es obligatorio.","security":[{"managerBearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["comentario_admin"],"properties":{"comentario_admin":{"type":"string","description":"Motivo de rechazo (obligatorio)"}}}}}},"responses":{"200":{"description":"Solicitud rechazada"},"400":{"description":"Comentario requerido o solicitud ya procesada"},"403":{"description":"Sin acceso a la sede"},"404":{"description":"Solicitud no encontrada"}}}},"/api/manager/curp/{curp}":{"get":{"tags":["Manager Utils"],"summary":"Validar CURP vía proxy","description":"Proxy al servicio de validación CURP. El token de autenticación vive en el backend\npara no exponerlo al frontend.\n","security":[{"managerBearerAuth":[]}],"parameters":[{"in":"path","name":"curp","required":true,"schema":{"type":"string","minLength":18,"maxLength":18},"description":"CURP a validar (18 caracteres)","example":"PELJ850101HDFRPN09"}],"responses":{"200":{"description":"Resultado de la validación CURP"},"400":{"description":"CURP debe tener 18 caracteres"},"500":{"description":"Token de CURP no configurado"},"502":{"description":"Error al consultar servicio CURP"}}}},"/api/pacientes/{id_paciente}/medicamentos-activos":{"get":{"tags":["Medicamentos Activos"],"summary":"Listar medicamentos activos del paciente","description":"Devuelve los medicamentos activos (fecha_fin NULL o futura)\nasociados a las consultas del paciente. Se alimenta automáticamente\nal crear consultas con prescripciones.\n","parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Lista de medicamentos activos","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id_medicamento":{"type":"integer"},"id_consulta":{"type":"integer"},"medicamento":{"type":"string"},"medicamento_clave":{"type":"string","nullable":true},"fecha_inicio":{"type":"string","format":"date"},"fecha_fin":{"type":"string","format":"date","nullable":true},"fechaConsulta":{"type":"string","format":"date"}}}}}}}}}},"/api/pacientes/{id_paciente}/medicamentos-activos/{id_medicamento}":{"put":{"tags":["Medicamentos Activos"],"summary":"Actualizar medicamento (ej. dar de baja con fecha_fin)","parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}},{"in":"path","name":"id_medicamento","required":true,"schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"fecha_fin":{"type":"string","format":"date","description":"Fecha de baja del medicamento"}}}}}},"responses":{"200":{"description":"Medicamento actualizado"},"404":{"description":"Medicamento no encontrado"}}}},"/api/mis-medicamentos":{"get":{"tags":["Mis Medicamentos"],"summary":"Listar medicamentos propios del médico","description":"Devuelve los medicamentos que el médico ha creado en su catálogo personal (tabla cat__medicamento)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Lista de medicamentos del médico","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","properties":{"id_medicamento":{"type":"integer"},"nombre":{"type":"string"},"formula":{"type":"string"},"presentacion":{"type":"string"},"gramaje":{"type":"string"},"via":{"type":"string"}}}}}}}}}}},"post":{"tags":["Mis Medicamentos"],"summary":"Crear medicamento propio","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["nombre"],"properties":{"nombre":{"type":"string","example":"Vaporub"},"formula":{"type":"string","example":"Mentol, Alcanfor, Eucalipto"},"presentacion":{"type":"string","example":"Ungüento"},"gramaje":{"type":"string","example":"12 g"},"via":{"type":"string","example":"Tópica"}}}}}},"responses":{"201":{"description":"Medicamento creado"}}}},"/api/mis-medicamentos/{id}":{"put":{"tags":["Mis Medicamentos"],"summary":"Actualizar medicamento propio","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"},"description":"id_medicamento"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["nombre"],"properties":{"nombre":{"type":"string"},"formula":{"type":"string"},"presentacion":{"type":"string"},"gramaje":{"type":"string"},"via":{"type":"string"}}}}}},"responses":{"200":{"description":"Medicamento actualizado"}}},"delete":{"tags":["Mis Medicamentos"],"summary":"Eliminar medicamento propio","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"},"description":"id_medicamento"}],"responses":{"200":{"description":"Medicamento eliminado"}}}},"/api/pacientes":{"get":{"tags":["Pacientes"],"summary":"Listar pacientes del médico","parameters":[{"in":"query","name":"page","schema":{"type":"integer","default":1},"description":"Página"},{"in":"query","name":"limit","schema":{"type":"integer","default":20},"description":"Resultados por página"},{"in":"query","name":"buscar","schema":{"type":"string"},"description":"Buscar por nombre, apellido o CURP"}],"responses":{"200":{"description":"Lista paginada de pacientes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PacienteListResponse"}}}}}},"post":{"tags":["Pacientes"],"summary":"Crear paciente","description":"Crea un paciente aplicando validaciones GIIS:\n- CURP (GIIS#9), Nombres (GIIS#10-12), Sexo (GIIS#16-17)\n- Género (GIIS#22), Derechohabiencia (GIIS#23)\n- Migrante/País procedencia (GIIS#20-21)\n- Entidad nacimiento (GIIS#15) según país\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PacienteCreate"}}}},"responses":{"201":{"description":"Paciente creado","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"id_paciente":{"type":"integer"}}}}}},"400":{"description":"Errores de validación GIIS","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"CURP duplicada para este médico"}}}},"/api/pacientes/{id}":{"get":{"tags":["Pacientes"],"summary":"Obtener paciente por ID","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Datos del paciente","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PacienteResponse"}}}},"404":{"description":"Paciente no encontrado"}}},"put":{"tags":["Pacientes"],"summary":"Actualizar paciente","description":"Actualiza campos del paciente. Solo se envían los campos a modificar.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PacienteCreate"}}}},"responses":{"200":{"description":"Paciente actualizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"Errores de validación GIIS"},"404":{"description":"Paciente no encontrado"}}},"delete":{"tags":["Pacientes"],"summary":"Desactivar paciente (soft delete)","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Paciente desactivado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"404":{"description":"Paciente no encontrado"}}}},"/api/pacientes/{id_paciente}/documentos":{"get":{"tags":["Documentos Clínicos"],"summary":"Listar documentos del paciente","description":"Retorna el historial completo de documentos clínicos generados para el paciente por el médico autenticado (consentimientos, altas, avisos, etc.), ordenados por fecha descendente.\n","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"},"description":"ID del paciente"}],"responses":{"200":{"description":"Lista de documentos clínicos","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PacienteDocumentoResponse"}}}}},"401":{"description":"No autorizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Documentos Clínicos"],"summary":"Generar documento clínico para el paciente","description":"Crea un nuevo documento clínico en el historial del paciente. El campo `texto_final` debe contener el texto ya con las variables sustituidas (`{{NOMBRE_PACIENTE}}`, `{{MEDICO}}`, `{{FECHA}}`, `{{ESPECIALIDAD}}`). El documento se crea en estado vigente (status=1) y sin firmar (firmado=0).\n","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PacienteDocumentoCreate"}}}},"responses":{"201":{"description":"Documento generado exitosamente","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Documento creado"},"id_documento":{"type":"integer","example":15}}}}}},"400":{"description":"Datos inválidos","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No autorizado"}}}},"/api/pacientes/{id_paciente}/documentos/{id_documento}":{"get":{"tags":["Documentos Clínicos"],"summary":"Obtener un documento por ID","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}},{"in":"path","name":"id_documento","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Documento encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PacienteDocumentoResponse"}}}},"401":{"description":"No autorizado"},"404":{"description":"Documento no encontrado"}}}},"/api/pacientes/{id_paciente}/documentos/{id_documento}/firmar":{"patch":{"tags":["Documentos Clínicos"],"summary":"Registrar firma del paciente","description":"Marca el documento como firmado por el paciente y registra la fecha y hora de la firma. Solo se puede firmar un documento vigente (status=1) que no haya sido firmado previamente.\n","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}},{"in":"path","name":"id_documento","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Documento firmado correctamente","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"El documento ya fue firmado o está anulado"},"401":{"description":"No autorizado"},"404":{"description":"Documento no encontrado"}}}},"/api/pacientes/{id_paciente}/documentos/{id_documento}/anular":{"patch":{"tags":["Documentos Clínicos"],"summary":"Anular documento clínico","description":"Cambia el status del documento a 0 (anulado). Un documento anulado no puede ser firmado ni modificado. Esta acción no elimina el registro del historial.\n","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}},{"in":"path","name":"id_documento","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Documento anulado correctamente","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"El documento ya está anulado"},"401":{"description":"No autorizado"},"404":{"description":"Documento no encontrado"}}}},"/api/pacientes/{id_paciente}/documentos/{id_documento}/observaciones":{"patch":{"tags":["Documentos Clínicos"],"summary":"Actualizar observaciones del documento","description":"Permite al médico editar las notas/observaciones adicionales de un documento vigente. No es posible modificar observaciones de documentos anulados.\n","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id_paciente","required":true,"schema":{"type":"integer"}},{"in":"path","name":"id_documento","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["observaciones"],"properties":{"observaciones":{"type":"string","nullable":true,"example":"Paciente firmó con testigo presente."}}}}}},"responses":{"200":{"description":"Observaciones actualizadas","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"400":{"description":"Campo observaciones requerido"},"401":{"description":"No autorizado"},"404":{"description":"Documento no encontrado o está anulado"}}}},"/api/medico/preferencias":{"patch":{"tags":["Médico"],"summary":"Actualizar preferencias del médico","description":"Actualiza las preferencias personales del médico autenticado.\nActualmente soporta:\n- **tour_home_visto** (0 | 1): Indica si el médico ya vio el tour de onboarding del Home.\n  Enviar `0` para resetearlo (relanzar tour desde Mi cuenta).\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tour_home_visto":{"type":"integer","enum":[0,1],"example":1}}}}}},"responses":{"200":{"description":"Preferencias actualizadas","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"tour_home_visto":{"type":"integer","example":1}}}}}},"400":{"description":"Campo inválido o valor fuera de rango"},"401":{"description":"Token inválido o expirado"}}}},"/api/instituciones":{"get":{"tags":["Sedes"],"summary":"Listar instituciones del médico","responses":{"200":{"description":"Lista de instituciones"}}}},"/api/instituciones/{id}":{"get":{"tags":["Sedes"],"summary":"Obtener institución por ID","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Datos de la institución"},"404":{"description":"Institución no encontrada"}}}},"/api/sedes":{"get":{"tags":["Sedes"],"summary":"Listar sedes del médico","description":"Incluye rol y permisos del médico en cada sede.","responses":{"200":{"description":"Lista de sedes con permisos"}}},"post":{"tags":["Sedes"],"summary":"Crear sede","description":"Crea una sede y vincula al médico como titular.\nSi se proporciona CLUES, debe ser de 11 caracteres (GIIS#1).\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SedeCreate"}}}},"responses":{"201":{"description":"Sede creada","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"id_sede":{"type":"integer"}}}}}},"400":{"description":"CLUES inválida"}}}},"/api/sedes/{id}":{"get":{"tags":["Sedes"],"summary":"Obtener sede por ID","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Datos de la sede"},"404":{"description":"Sede no encontrada"}}},"put":{"tags":["Sedes"],"summary":"Actualizar sede","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SedeCreate"}}}},"responses":{"200":{"description":"Sede actualizada"},"400":{"description":"CLUES inválida"},"404":{"description":"Sede no encontrada"}}}},"/api/medico/storage":{"get":{"tags":["Archivos"],"summary":"Storage total usado por el médico autenticado (todos sus pacientes)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Bytes usados, total de archivos y límite","content":{"application/json":{"schema":{"type":"object","properties":{"bytes_usados":{"type":"integer","example":5242880},"total_archivos":{"type":"integer","example":12},"limite_bytes":{"type":"integer","example":104857600}}}}}}}}},"/api/medico/storage/solicitar":{"post":{"tags":["Archivos"],"summary":"Solicitar ampliación de almacenamiento al manager","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["bytes_solicitado"],"properties":{"bytes_solicitado":{"type":"integer","description":"Nuevo límite solicitado en bytes"},"motivo":{"type":"string","description":"Motivo de la solicitud"}}}}}},"responses":{"201":{"description":"Solicitud enviada"},"409":{"description":"Ya existe una solicitud pendiente"}}}},"/api/tickets":{"post":{"tags":["Tickets"],"summary":"Crear un ticket de soporte","description":"El médico autenticado crea un ticket. Se envía notificación por correo.","requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","required":["descripcion","categoria","asunto"],"properties":{"descripcion":{"type":"string"},"categoria":{"type":"string"},"asunto":{"type":"string"},"archivo":{"type":"array","items":{"type":"string","format":"binary"}}}}}}},"responses":{"201":{"description":"Ticket creado"},"400":{"description":"Campos faltantes"}}},"get":{"tags":["Tickets"],"summary":"Listar tickets del médico autenticado","responses":{"200":{"description":"Lista de tickets con comentarios"}}}},"/api/tickets/{id}":{"get":{"tags":["Tickets"],"summary":"Detalle de un ticket con archivos y comentarios","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Ticket completo"},"404":{"description":"Ticket no encontrado"}}}},"/api/tickets/{id}/comment":{"post":{"tags":["Tickets"],"summary":"Responder/comentar en un ticket","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"integer"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","required":["comment"],"properties":{"comment":{"type":"string"},"archivo":{"type":"array","items":{"type":"string","format":"binary"}}}}}}},"responses":{"201":{"description":"Comentario enviado"},"400":{"description":"Comentario vacío"},"404":{"description":"Ticket no encontrado"}}}},"/api/transcribir":{"post":{"tags":["Transcripción"],"summary":"Transcribir audio a texto","description":"Recibe un archivo de audio (WebM, OGG, MP3, WAV, M4A) y lo transcribe\na texto en español usando OpenAI Whisper. Diseñado para dictado médico\ndesde el componente DictationTextarea del frontend.\n","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["audio"],"properties":{"audio":{"type":"string","format":"binary","description":"Archivo de audio a transcribir (máx 25 MB)"}}}}}},"responses":{"200":{"description":"Transcripción exitosa","content":{"application/json":{"schema":{"type":"object","properties":{"texto":{"type":"string","example":"El paciente presenta dolor abdominal en el cuadrante inferior derecho."}}}}}},"400":{"description":"No se recibió archivo de audio o formato inválido"},"401":{"description":"Token no proporcionado o inválido"},"429":{"description":"Límite de uso de OpenAI alcanzado"},"500":{"description":"Error interno o API key no configurada"}}}}}}