# 馃攳 Casos de Borde - An谩lisis Uno por Uno ## 馃幆 Objetivo Estudiar caso por caso todos los edge cases posibles en la aplicaci贸n m茅dica. --- ## 1. Dosis Pedi谩tricas ### Caso 1.1: Peso = 0 o negativo **Problema:** Divisi贸n por cero o c谩lculo inv谩lido **Soluci贸n:** ```typescript class PatientWeight { static fromKg(kg: number): PatientWeight { if (kg <= 0) { throw new Error('Peso debe ser mayor que cero'); } if (kg > 200) { throw new Error('Peso excesivo, verificar entrada'); } return new PatientWeight(kg, 'kg'); } } ``` **Validaci贸n:** Bloquear c谩lculo si peso <= 0 --- ### Caso 1.2: Peso fuera de rango para edad **Problema:** Ni帽o de 5 a帽os con peso de 100kg (imposible) **Soluci贸n:** ```typescript isValidForAge(age: PatientAge): { valid: boolean; warning?: string } { const range = age.getWeightRange(); const weightKg = this.toKg(); if (weightKg < range.min * 0.5) { return { valid: false, warning: `Peso extremadamente bajo. Verificar entrada.` }; } if (weightKg > range.max * 2) { return { valid: false, warning: `Peso extremadamente alto. Verificar entrada.` }; } return { valid: true }; } ``` **Validaci贸n:** Bloquear si peso < 50% del m铆nimo O > 200% del m谩ximo --- ### Caso 1.3: Dosis pedi谩trica no definida **Problema:** F谩rmaco sin dosis pedi谩trica pero se intenta calcular **Soluci贸n:** ```typescript async calculatePediatricDose(...): Promise { if (!drug.pediatricDose) { throw new Error( `No hay dosis pedi谩trica definida para ${drug.genericName}. ` + `Usar dosis adulto con precauci贸n o consultar referencia.` ); } // ... } ``` **Validaci贸n:** Bloquear c谩lculo, mostrar advertencia --- ### Caso 1.4: C谩lculo resulta en dosis < 0.01mg **Problema:** Dosis muy peque帽a, dif铆cil de medir **Soluci贸n:** ```typescript if (calculatedDose < 0.01) { warnings.push( `Dosis calculada (${calculatedDose}mg) es muy peque帽a para medir con precisi贸n. ` + `Considerar diluci贸n o consultar referencia especializada.` ); } ``` **Validaci贸n:** Advertencia, no bloquea --- ## 2. Protocolos ### Caso 2.1: Protocolo sin pasos **Problema:** Protocolo creado sin pasos definidos **Soluci贸n:** ```typescript static create(...): Protocol { if (!steps || steps.length === 0) { throw new Error('Protocolo debe tener al menos un paso'); } // ... } ``` **Validaci贸n:** Bloquear creaci贸n/validaci贸n --- ### Caso 2.2: Pasos con n煤meros duplicados **Problema:** Dos pasos con order = 3 **Soluci贸n:** ```typescript static create(steps: ProtocolStep[]): ProtocolSequence { const orders = steps.map(s => s.order); const uniqueOrders = new Set(orders); if (orders.length !== uniqueOrders.size) { throw new Error('Hay pasos con el mismo n煤mero de orden'); } // ... } ``` **Validaci贸n:** Bloquear creaci贸n --- ### Caso 2.3: Pasos faltantes en secuencia **Problema:** Pasos 1, 2, 4, 5 (falta el 3) **Soluci贸n:** ```typescript for (let i = 0; i < sortedSteps.length; i++) { if (sortedSteps[i].order !== i + 1) { throw new Error( `Paso faltante en secuencia: esperado ${i + 1}, encontrado ${sortedSteps[i].order}` ); } } ``` **Validaci贸n:** Bloquear creaci贸n --- ### Caso 2.4: Protocolo prerequisito no existe **Problema:** Protocolo A requiere Protocolo B que no existe **Soluci贸n:** ```typescript async validateProtocolDependencies(...): Promise { for (const prereqId of protocol.prerequisites) { const prereq = await this.protocolRepository.findById(prereqId); if (!prereq) { errors.push(`Protocolo prerequisito "${prereqId}" no existe`); } } // ... } ``` **Validaci贸n:** Bloquear si prerequisito no existe --- ### Caso 2.5: Dependencia circular **Problema:** Protocolo A requiere B, B requiere A **Soluci贸n:** ```typescript async detectCircularDependency( protocolId: string, targetId: string, visited: Set = new Set() ): Promise { if (visited.has(protocolId)) { return protocolId === targetId; // Circular } visited.add(protocolId); const protocol = await this.protocolRepository.findById(protocolId); for (const prereqId of protocol.prerequisites) { if (await this.detectCircularDependency(prereqId, targetId, visited)) { return true; } } return false; } ``` **Validaci贸n:** Bloquear creaci贸n de dependencia circular --- ## 3. Contenido M茅dico ### Caso 3.1: Contenido sin t铆tulo **Problema:** Crear contenido con t铆tulo vac铆o **Soluci贸n:** ```typescript static create(...): ContentItem { if (!title || title.trim().length === 0) { throw new Error('T铆tulo es obligatorio'); } // ... } ``` **Validaci贸n:** Bloquear creaci贸n --- ### Caso 3.2: Intentar publicar sin validaci贸n m茅dica **Problema:** Publicar contenido que no ha sido revisado **Soluci贸n:** ```typescript async publishContent(...): Promise { if (content.status !== 'approved') { throw new Error('Solo contenido aprobado puede publicarse'); } if (!content.validatedBy) { throw new Error('Contenido debe estar validado por un m茅dico'); } // ... } ``` **Validaci贸n:** Bloquear publicaci贸n --- ### Caso 3.3: Contenido rechazado intenta publicarse **Problema:** Publicar contenido que fue rechazado **Soluci贸n:** ```typescript const rejectedReviews = reviews.filter(r => r.status === 'rejected'); if (rejectedReviews.length > 0 && content.status === 'draft') { // Contenido fue rechazado y est谩 en borrador // Permitir edici贸n pero no publicaci贸n directa } ``` **Validaci贸n:** Bloquear publicaci贸n hasta nueva revisi贸n --- ### Caso 3.4: Slug duplicado **Problema:** Dos contenidos con el mismo slug **Soluci贸n:** ```typescript async save(content: ContentItem): Promise { const existing = await this.findBySlug(content.slug); if (existing && existing.id !== content.id) { throw new Error(`Slug "${content.slug}" ya existe`); } // ... } ``` **Validaci贸n:** Bloquear creaci贸n/actualizaci贸n --- ## 4. B煤squeda ### Caso 4.1: B煤squeda vac铆a **Problema:** Query string vac铆o **Soluci贸n:** ```typescript if (!search || search.trim().length === 0) { return { items: [], total: 0 }; } ``` **Validaci贸n:** Retornar resultados vac铆os, no error --- ### Caso 4.2: B煤squeda sin resultados **Problema:** No hay resultados para la b煤squeda **Soluci贸n:** ```typescript if (results.length === 0) { return { items: [], total: 0, suggestions: await this.getSearchSuggestions(search) }; } ``` **Validaci贸n:** Retornar sugerencias, no error --- ### Caso 4.3: B煤squeda con caracteres especiales **Problema:** SQL injection o caracteres problem谩ticos **Soluci贸n:** ```typescript const sanitized = search.trim().replace(/[%_]/g, '\\$&'); // Usar par谩metros preparados siempre ``` **Validaci贸n:** Sanitizar entrada, usar par谩metros preparados --- ## 5. Offline ### Caso 5.1: Contenido cr铆tico no en cache **Problema:** Usuario offline, contenido cr铆tico no disponible **Soluci贸n:** ```typescript async getContent(id: string): Promise { // Intentar cache primero const cached = await cache.get(`content:${id}`); if (cached) return cached; // Si offline y cr铆tico, retornar versi贸n m铆nima if (isOffline() && isCritical(id)) { return getMinimalCriticalContent(id); } return null; } ``` **Validaci贸n:** Retornar versi贸n m铆nima si cr铆tico, error si no cr铆tico --- ### Caso 5.2: Cache corrupto **Problema:** Datos en cache corruptos o incompletos **Soluci贸n:** ```typescript try { const cached = JSON.parse(cacheData); if (!isValidContent(cached)) { throw new Error('Cache corrupto'); } return cached; } catch (error) { // Limpiar cache y recargar await cache.delete(key); return await loadFromSource(id); } ``` **Validaci贸n:** Validar integridad, limpiar si corrupto --- ## 6. Validaci贸n M茅dica ### Caso 6.1: Revisor intenta aprobar su propio contenido **Problema:** Conflicto de intereses **Soluci贸n:** ```typescript async approveContent(...): Promise { if (content.createdBy === reviewerId) { throw new Error('No puedes aprobar tu propio contenido'); } // ... } ``` **Validaci贸n:** Bloquear auto-aprobaci贸n --- ### Caso 6.2: M煤ltiples revisores aprueban simult谩neamente **Problema:** Race condition **Soluci贸n:** ```typescript // Usar transacci贸n con lock await db.transaction(async (tx) => { const content = await tx.query( 'SELECT * FROM content_items WHERE id = $1 FOR UPDATE', [contentId] ); if (content.status !== 'in_review') { throw new Error('Estado cambi贸 durante la revisi贸n'); } // Actualizar... }); ``` **Validaci贸n:** Usar locks de base de datos --- ## 7. Medios Audiovisuales ### Caso 7.1: Archivo demasiado grande **Problema:** Upload de archivo > l铆mite **Soluci贸n:** ```typescript const MAX_SIZE = 50 * 1024 * 1024; // 50MB if (file.size > MAX_SIZE) { throw new Error(`Archivo excede tama帽o m谩ximo (${MAX_SIZE / 1024 / 1024}MB)`); } ``` **Validaci贸n:** Rechazar upload --- ### Caso 7.2: Tipo de archivo no permitido **Problema:** Upload de archivo .exe o .bat **Soluci贸n:** ```typescript const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'video/mp4', ...]; if (!ALLOWED_TYPES.includes(file.mimetype)) { throw new Error(`Tipo de archivo no permitido: ${file.mimetype}`); } ``` **Validaci贸n:** Rechazar upload --- ### Caso 7.3: Archivo corrupto o inv谩lido **Problema:** Imagen corrupta que no se puede procesar **Soluci贸n:** ```typescript try { const image = await sharp(file.buffer).metadata(); if (!image.width || !image.height) { throw new Error('Imagen inv谩lida'); } } catch (error) { throw new Error('Archivo corrupto o inv谩lido'); } ``` **Validaci贸n:** Validar integridad antes de guardar --- ## 馃摑 Resumen de Validaciones | Caso | Severidad | Acci贸n | |------|-----------|--------| | Peso <= 0 | Cr铆tico | Bloquear | | Dosis fuera de rango | Cr铆tico | Bloquear | | Paso cr铆tico omitido | Cr铆tico | Bloquear | | Contenido sin validaci贸n | Cr铆tico | Bloquear publicaci贸n | | Peso fuera de percentiles | Advertencia | Mostrar, permitir con confirmaci贸n | | Dosis en l铆mites | Advertencia | Mostrar, permitir | | B煤squeda sin resultados | Info | Mostrar sugerencias | --- **Fin del documento**