Tareas
Documento histórico
Este documento se conserva solo para trazabilidad. Consulte el índice maestro para la fuente vigente.
# Tareas pendientes
Documento histórico — auditoría 2026-06-04
Este archivo contiene el plan de trabajo y los hallazgos de la auditoría del 2026-06-04, con extensiones del 2026-06-07. Para conocer el estado actual vigente de la APK, consultar estado-actual.md.
Checklist priorizado con todo lo identificado durante la auditoría, actualizado al 2026-06-04. Cada tarea tiene un ID, descripción, prioridad, archivos afectados y criterios de aceptación.
Cambio importante: a partir de la auditoría del 4 de junio de 2026, el archivo se reorganizó en tres bloques: (1) tareas ✅ completadas desde la última auditoría, (2) tareas ⏳ vigentes que siguen pendientes, (3) tareas 🆕 nuevas identificadas en esta revisión. La doc original cubría 27 tareas; este nuevo estado refleja el avance real del repositorio.
Leyenda de prioridades¶
- 🔴 Crítica: bloquea el uso de la app o tiene impacto directo en el usuario.
- 🟠 Alta: mejora importante de UX o de coherencia con la doc.
- 🟡 Media: mejora de calidad de código o de extensibilidad.
- 🟢 Baja: cosmético, limpieza o refactor sin impacto funcional.
✅ Bloque A — Tareas completadas desde la última auditoría¶
Estas tareas ya no están pendientes; se documentan para mantener la trazabilidad y como referencia.
✅ T-001: Crear los 4 drawables faltantes¶
Resolución: los 4 drawables están creados como PNG en app/src/main/res/drawable/:
ic_islabox_logo.png— isotipo: palmera azul en círculo con isla rojaic_islabox_logo2.png— logo horizontal (palmera + texto)ic_islabox_letra.png— solo texto "isla|box"ic_islabox_success.png— sello/badge de éxito con check
IslaImages.kt apunta a los 4 IDs y WelcomeScreen, SuccessScreen, IslaDashboardTopBar e IslaTopBar los consumen sin crashear. La doc original sugería VectorDrawable (.xml); terminó siendo PNG. No bloquea y el visual es correcto.
✅ T-002: Corregir el identificador del casillero hardcodeado¶
Resolución: CurrentUser.kt ahora usa lockerId = "CP-001042-8" (correcto por Mod-10). DashboardScreen y PerfilScreen lo muestran sin hardcodear. Coincide con la doc.
La decisión sobre valores definitivos (días gratis, costo por día, etc.) se documenta en ../../../roadmap/preguntas.md.
La decisión sobre valores definitivos (días gratis, costo por día, etc.) se documenta en ../../../roadmap/preguntas.md.
✅ T-003: Declarar permisos faltantes en el AndroidManifest¶
Resolución: AndroidManifest.xml declara los 5 permisos:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
✅ T-101: Crear FakeDataSource central con datos de muestra¶
Resolución: app/src/main/java/com/example/islabox/data/local/FakeDataSource.kt existe como object con:
currentUser(1 User con KYC status)recipients(3 destinatarios en Cuba)reports(5 reportes con mezcla de estados)serviceRequests(2 solicitudes iniciales, lista mutable)charges,invoices,quotes(datos auxiliares)packageSummarycalculado dinámicamente desdereports(no hardcoded)
✅ T-102: Quitar datos hardcodeados de cada pantalla¶
Resolución: DashboardScreen y PerfilScreen ahora leen de CurrentUser.user. El packageSummary se calcula en FakeDataSource. RemitenteSelector recibe userName por parámetro. CurrentUser es un object global, no un mutableStateOf local.
✅ T-103: Iniciales del avatar calculadas¶
Resolución: User.kt define una propiedad derivada:
val initials: String get() = "${firstName.firstOrNull()?.uppercaseChar() ?: ""}${lastName.firstOrNull()?.uppercaseChar() ?: ""}"
ProfileHeader recibe initials por parámetro. Para "Kleudy Victor Torno Peña" muestra "KT".
✅ T-104: Decidir entre separar Reporte o mantenerlo unificado¶
Resolución: se eligió la Opción C — Híbrido. Reporte ahora tiene:
purchaseStatus: PurchaseReportStatus(estados administrativos)packageStatus: PhysicalPackageStatus?(estados físicos, nullable para prealertas sin paquete)
Además existe una propiedad de conveniencia estado: String que prioriza el estado físico sobre el administrativo, para mantener compatibilidad con UI previa.
✅ T-105: Cambiar Reporte.estado: String por enums¶
Resolución: se creó el paquete app/src/main/java/com/example/islabox/domain/enums/ con enums principales:
KycStatus(9 valores)DocumentType(3 valores)PurchaseReportStatus(7 valores — la doc define 8, se documenta la diferencia en T-405)PhysicalPackageStatus(10 valores)ConsolidationStatus(8 valores, exactamente alineados con la doc)PaymentStatus(5 valores)ShipmentStatus(16 valores consteppara timeline)ServiceTypeyServiceStatus(enServiceRequest.kt)AcceptanceyRiskLevel(enCustomsCategory.kt)LockerCodeStatus(enLockerCode.kt)
✅ T-106: Crear LockerCode data class con algoritmo Mod-10¶
Resolución:
LockerCode.kt— data class@Serializableconprefix,sequential,checkDigit,fullCode,normalized,statusy enumLockerCodeStatus { ACTIVE, INACTIVE, BLOCKED }.LockerCodeGenerator.kt— implementacalculateCheckDigit,normalize,validate(sealed conValid/Invalid(reason)),formatygenerate.- Tests unitarios pendientes (ver T-410).
✅ T-107: Crear KycRecord data class¶
Resolución: KycRecord.kt cubre los 13 campos de la doc, incluyendo submittedAt, expiresAt (10 años), reviewedBy, reviewedAt, rejectionReason. CurrentUser.user ahora incluye kycStatus: KycStatus y se muestra en el dashboard mediante KycBanner.
✅ T-108: Crear ServiceRequest data class¶
Resolución: ServiceRequest.kt con 4 ServiceType (Inspección Visual, Prueba Funcional, Reempaque, Devolución) y 10 ServiceStatus. Lista de serviceRequests en FakeDataSource.
✅ T-109: Crear CustomsCategory con metadata¶
Resolución: CustomsCategory.kt con las 15 categorías operativas, cada una con code, name, description, accepted, requiresInvoice, requiresReview, riskLevel, allowsAir, allowsSea, dutyPercentage, userMessage, operatorMessage. Las diferencias con la doc de aduana (ej. "electrodomésticos" sin equivalente directo) están documentadas en T-405.
✅ T-110: Crear Consolidation + ConsolidationPackage¶
Resolución: ambas data classes existen. Consolidation con 8 estados y campos totalWeight, totalValue, packageCount, shippingAddressId, trackingNumber. ConsolidationPackage con la relación N:N. Falta: pantalla de creación de consolidación (ver T-406).
✅ T-111: Crear entidades de dinero (Quote, Payment, Charge, Invoice)¶
Resolución: las 4 entidades existen en domain/model/:
QuoteconQuoteItem(subtotales, descuentos, expiración)PaymentconPaymentMethodMix(desglose real/credit/card)Charge(categorías: shipping, insurance, storage, customFees, etc.)InvoiceconList<Charge>,List<Payment>, dueDate, paidAt
Falta: pantallas de pago, cotización y factura (ver T-404, T-406, T-407).
✅ T-202: Mover datos del usuario a constantes reutilizables¶
Resolución: AppSettings.kt existe en core/config/ y centraliza:
// ⚠️ Tarea abierta: actualizar a los valores resueltos (ver [preguntas.md](../../../roadmap/preguntas.md))
const val FREE_STORAGE_DAYS = 5 // debe ser 15
const val STORAGE_DAILY_COST = 1.00 // debe ser 0.50
const val STORAGE_WARNING_DAYS = 1
Decisión resuelta 2026-06-06 (preguntas.md):
- FREE_STORAGE_DAYS → 15
- STORAGE_DAILY_COST → 0.50
Tanto StorageInfoCard como StorageControl consumen estas constantes.
✅ T-203: Decidir qué hacer con los componentes envios/ huérfanos¶
Resolución: la carpeta ui/components/envios/ ya no es huérfana. ShipmentTimeline está integrado en ShipmentDetailScreen.kt. Falta: navegar desde el dashboard (ver T-403).
✅ T-204: Eliminar pantalla huérfana ReporteScreen (parcial)¶
Resolución: ReporteScreen.kt ya no aparece en el grafo de navegación ni en list_dir ui/screens/main. ReportesScreen lo reemplazó. Verificar que el archivo no exista físicamente (ver T-411).
✅ T-205: Eliminar SampleModel y SampleRepository (parcial)¶
Resolución: SampleRepository ya no existe. Falta confirmar que SampleModel.kt también se haya borrado (ver T-411).
✅ T-206: Unificar días gratis de almacenaje¶
Resolución parcial (código): StorageInfoCard y StorageControl ahora leen de AppSettings.FREE_STORAGE_DAYS. Ya no hay desincronización entre componentes.
Pendiente (decisión de negocio resuelta 2026-06-06): actualizar el valor de la constante a 15 días y STORAGE_DAILY_COST a $0.50 USD según preguntas.md. Tarea nueva derivada: T-206b — actualizar AppSettings.kt y verificar que las pruebas (StorageInfoCard, StorageControl) sigan pasando. (Ver criterios de almacenaje.)
✅ T-208: Reemplazar paso de Reporte completo en URL por id¶
Resolución: Screen.ReporteDetalle ahora es:
@Serializable data class ReporteDetalle(val reporteId: String) : Screen()
ReporteDetalleScreen busca el reporte en FakeDataSource por id y muestra un Reporte() vacío si no se encuentra (deep link seguro).
✅ T-209: Mover OtpInputField a common/¶
Resolución: OtpInputField.kt está en ui/components/common/ y se importa desde VerificationCodeScreen.
✅ T-210: Implementar validaciones inline en el formulario de reporte¶
Resolución: ReporteFormValidations.kt implementa validateTracking (regex ^[A-Z0-9]{5,}$), validateValor (número > 0) y validateFecha (formato DD/MM/AAAA con validación de días por mes, incluyendo bisiestos). Los errores se muestran inline y el botón "Enviar" se deshabilita.
✅ T-301 a T-306: Pantallas KYC completas¶
Resolución: las 7 pantallas del flujo KYC están implementadas y conectadas: KycWelcomeScreen, KycDocumentTypeScreen, KycDocumentFrontScreen, KycDocumentBackScreen, KycSelfieScreen, KycResidenceScreen (con las 16 provincias de Cuba) y KycReviewScreen (+ KycSubmittedScreen). KycCamera.kt gestiona el permiso de cámara y simula la captura (integración CameraX pendiente en T-408). El KycBanner se muestra en el dashboard con copy distinto según el estado.
✅ T-401: Decidir la sección "Envíos" del Dashboard¶
Resolución: se eligió la Opción A — 4 secciones. PackageSummarySection muestra 4 contadores (En almacén, Enviados, En tránsito, Entregados) y cada uno navega a PaquetesScreen con el filtro correspondiente. PaquetesFilter es un enum con ALL, IN_TRANSIT, IN_WAREHOUSE, IN_SHIPMENT, DELIVERED y su método matches(reporte).
✅ T-402: Pantalla de detalle de envío¶
Resolución: ShipmentDetailScreen.kt está creada y usa el ShipmentTimeline con los 16 estados del enum ShipmentStatus. Muestra tienda, tracking, estado actual, info de aduana (cuando status >= EN_ADUANA_DESTINO), costo final y fecha estimada. Falta: navegación desde la lista de paquetes o desde ReporteDetalleScreen (ver T-403).
✅ T-501: Lista de servicios solicitados¶
Resolución: ServiceRequestsListScreen.kt lista los ServiceRequest del usuario con filtros por ServiceType y ServiceStatus mediante FilterChip.
✅ T-502: Pantalla de solicitar inspección¶
Resolución: RequestInspectionScreen.kt permite crear un nuevo ServiceRequest con tipo, descripción y fotos. Crea el request con status = REQUESTED y lo añade a FakeDataSource.serviceRequests.
✅ T-503: Pantalla de solicitar devolución¶
Resolución: RequestReturnScreen.kt está creada con el mismo patrón que RequestInspectionScreen. Navega desde ReporteDetalleScreen.
✅ ProGuard: Reglas para kotlinx-serialization¶
Resolución: proguard-rules.pro ya tiene las reglas mínimas para mantener $Companion, $serializer y INSTANCE de las clases @Serializable cuando se activa isMinifyEnabled = true en release.
✅ Migración a Java 17¶
Resolución: compileOptions en app/build.gradle.kts usa JavaVersion.VERSION_17 (la doc mencionaba Java 11, pero la implementación migró a 17). Esto es coherente con AGP 9.x y Compose Compiler 2.2.10.
⏳ Bloque B — Tareas vigentes (aún pendientes)¶
Estas tareas estaban en la doc anterior y siguen sin resolverse.
🔴 T-201: Implementar handler de onRegisterClick¶
Por qué: RegisterScreen llama a onRegisterClick(name, email, phone, password) pero el NavGraph lo ignora (handler { _, _, _, _ -> }). El usuario queda en la pantalla de registro sin avanzar.
Archivos a modificar:
app/src/main/java/com/example/islabox/ui/navigation/NavGraph.kt— en el bloquecomposable<Screen.Register>.
Cambio:
composable<Screen.Register> {
RegisterScreen(
onRegisterClick = { _, _, _, _ ->
// MVP: navegar directamente a Main, simulando registro exitoso.
// Cuando haya backend, llamar al endpoint y mostrar Success/Error.
navController.navigate(Screen.Main) {
popUpTo(Screen.Welcome) { inclusive = true }
}
},
...
)
}
Criterios de aceptación:
- Click en "Registrarse" navega a
Main. - El usuario ve el dashboard con el banner de KYC (porque sigue sin KYC).
- No hay crashes ni pantallas en blanco.
🟠 T-403: Conectar ShipmentDetailScreen desde PaquetesScreen y ReporteDetalleScreen¶
Estado al 2026-06-07: ✅ Resuelto. MainScreen.kt:54-65 redirige a ShipmentDetail cuando packageStatus == DESPACHADO. La ruta Screen.ShipmentDetail(val reporteId: String) está registrada en NavGraph.kt y ShipmentDetailScreen parsea el ShipmentStatus desde el string.
Por qué: la pantalla existe pero no es accesible desde ningún lado. El usuario no puede ver el detalle de un envío.
Archivos a modificar:
app/src/main/java/com/example/islabox/ui/navigation/NavGraph.kt— registrar la ruta.app/src/main/java/com/example/islabox/ui/screens/main/PaquetesScreen.kt— pasar elShipmentcorrespondiente.app/src/main/java/com/example/islabox/ui/screens/reporte/ReporteDetalleScreen.kt— botón "Ver envío".
Cambio sugerido:
@Serializable data class ShipmentDetail(val reporteId: String) : Screen()
Criterios de aceptación:
- Click en un paquete con
packageStatus = DESPACHADOabre suShipmentDetailScreen. ✅ - El
ShipmentDetailScreenmuestra elShipmentTimelinecon el paso actual. ✅ - Botón back navega a la lista anterior. ✅
🟠 T-404: Pantallas de pago y cotización¶
Estado al 2026-06-07: ✅ Resuelto. Las 3 pantallas existen:
- QuoteScreen.kt muestra cotización con desglose y botón "Aceptar".
- PaymentScreen.kt con 3 métodos (Efectivo/Crédito/Tarjeta), desglose en tiempo real, validación de monto completo, navega a Invoice.
- InvoiceScreen.kt con detalle de cargos, icono de éxito, navega a Main.
Navegación: Quote → Payment → Invoice → Main. Todo con datos mockeados de FakeDataSource. Falta integración real con Stripe (T-422).
Por qué: los modelos Quote, Payment, Invoice existen pero no hay UI.
Archivos a crear:
app/src/main/java/com/example/islabox/ui/screens/servicios/QuoteScreen.kt— muestra unaQuotecon desglose.app/src/main/java/com/example/islabox/ui/screens/servicios/PaymentScreen.kt— selecciona método (real/credit/card) y confirma.app/src/main/java/com/example/islabox/ui/screens/servicios/InvoiceScreen.kt— lista de cargos + pagos.
Criterios de aceptación:
- El usuario puede ver el desglose de un envío antes de pagar. ✅
- Puede confirmar el pago y ver la factura resultante. ✅
- El
paymentMethodMixse desglosa correctamente. ✅ - Procesar cargo real (T-422).
🟠 T-405: Alinear CustomsCategory y Reporte.estado con la doc¶
Por qué: hay pequeñas diferencias entre los enums de la app y los definidos en datos/estados.md y datos/aduana.md.
Diferencias detectadas:
Doc (datos/estados.md) |
App actual | Acción |
|---|---|---|
borrador (8 estados prealerta) |
No implementado en PurchaseReportStatus |
Agregar DRAFT |
reportada_sin_tracking |
Renombrado a PENDIENTE_TRACKING |
Renombrar para alinear |
tracking_actualizado |
Renombrado a TRACKING_RECIBIDO |
Renombrar para alinear |
vinculada_a_paquete |
No existe en PurchaseReportStatus |
Agregar |
cancelada_por_usuario |
CANCELADA |
Renombrar |
cancelada_por_operador |
No existe | Agregar |
requiere_correccion |
Renombrado a ERROR_DATOS |
Renombrar |
16 estados de physical_packages |
10 implementados | Agregar los 6 que faltan (prealertado, recibido_sin_identificar, recibido_identificado, pendiente_conciliacion, esperando_instrucciones, reservado_para_consolidacion, devuelto_a_tienda, descartado_o_cerrado) |
| 15 categorías aduaneras (doc) | 15 implementadas (app) | Coinciden ✅, pero los nombres difieren en algunos casos. Verificar nomenclatura. |
Criterios de aceptación:
- Los 8 estados de prealerta están en
PurchaseReportStatus. - Los 16 estados de paquete físico están en
PhysicalPackageStatus. - Las 15 categorías tienen los nombres exactos de la doc.
🔴 T-406: Maquetación del flujo de consolidación (CU-007) — MAQUETACIÓN, sin backend¶
Por qué: la auditoría 2026-06-07 detectó que ConsolidationListScreen y ConsolidationDetailScreen existen, pero el usuario no puede crear una consolidación propia. Las dos consolidaciones que se ven en el dashboard (CON-001, CON-002) son estáticas de FakeDataSource. No hay:
- Pantalla de selección múltiple de paquetes.
- Pantalla de resumen (peso, vía, destinatario, costo).
- Selector de vía (Barco $2.40 / Avión $3.35).
- Validación de KYC aprobado.
- Generación de
Quotedesde consolidación. - Punto de entrada desde
ReporteDetalle("Agregar a consolidación" no hace nada). - Botón "Ver envío" desde
ReporteDetalleparaCONSOLIDADO(handler vacío).
Esto incumple el caso de uso CU-007 completo, que es Alta prioridad MVP.
Alcance MVP visual (sin backend): la consolidación se crea en memoria y se guarda en FakeDataSource.consolidations. No hay lock distribuido, ni cálculo de costo real contra un servidor de la agencia aliada. Las tarifas SHIPPING_RATE_SEA y SHIPPING_RATE_AIR se usan en el cálculo local. El lock y la persistencia real vendrán con el backend.
Archivos a crear / modificar:
app/src/main/java/com/example/islabox/ui/screens/reporte/ConsolidationCreateScreen.kt(nuevo, pantalla de selección).app/src/main/java/com/example/islabox/ui/screens/reporte/ConsolidationSummaryScreen.kt(nuevo, resumen + vía + destinatario + costo).x] DesdeReporteDetallecon estadoEN_ALMACENoLISTO_PARA_CONSOLIDAR`, el botón "Agregar a consolidación" abre la pantalla de selección. ✅- El usuario puede seleccionar 2+ paquetes y avanzar. ✅ (cualquier paquete seleccionable)
- La pantalla de resumen muestra peso total, vía seleccionable (Barco/Avión), destinatario y costo calculado. ✅
- Si el KYC no está aprobado, muestra pantalla de bloqueo con CTA a KYC. ✅ (
KycBlockedScreenenConsolidationCreate) - Al confirmar, crea la
ConsolidationenFakeDataSource, losConsolidationPackage, unaQuotecon vigencia 7 días y navega aQuoteScreencon el id real. ❌ Navega aCON-NEWficticio (T-417/Consolidation) - Desde
ConsolidationListScreenhay un FAB "Nueva consolidación" siempre visible. ✅ -
El dashboard no oculta la card "Tus consolidaciones" cuando
count == 0. ✅ (ConsolidationsActionCardcon CTA "Agrupa tus paquetes y ahorra en el envío") -
Desde
ReporteDetallecon estadoEN_ALMACENoLISTO_PARA_CONSOLIDAR, el botón "Agregar a consolidación" abre la pantalla de selección. - El usuario puede seleccionar 2+ paquetes y avanzar.
- La pantalla de resumen muestra peso total, vía seleccionable (Barco/Avión), destinatario y costo calculado.
- Si el KYC no está aprobado, muestra pantalla de bloqueo con CTA a KYC.
- Al confirmar, crea la
ConsolidationenFakeDataSource, losConsolidationPackage, unaQuotecon vigencia 7 días y navega aQuoteScreencon el id real. - Desde
ConsolidationListScreenhay un FAB "Nueva consolidación" siempre visible (no condicional acount > 0). - El dashboard no oculta la card "Tus consolidaciones" cuando
count == 0: debe mostrar CTA "Crear primera".
🟡 T-407: Pantalla de notificaciones con datos mockeados (maquetación)¶
Por qué: existe NotificationsScreen.kt pero solo tiene empty state. La doc define 18+ eventos.
Alcance MVP visual (sin backend): poblar la lista con Notification (data class) y 12 datos de muestra en FakeDataSource.notifications. No se generan por eventos reales.
Cambio: agregar data class Notification y poblar FakeDataSource.notifications con ejemplos de los 18+ eventos definidos en la doc (paquete recibido, en aduana, entregado, etc.). Conectar NotificationsScreen con LazyColumn para mostrar la lista.
🟡 T-408: Integración real con CameraX en KYC (no requiere backend, solo libs nativas)¶
Por qué: KycCamera simula la captura devolviendo un id timestamp. Falta la integración real.
Acción:
- Agregar
androidx.camera:camera-camera2,camera-lifecycle,camera-viewalibs.versions.toml. - Crear
KycCameraXque usePreviewView+ImageCapture. - Reemplazar
simulateCapture()por captura real.
Criterios de aceptación:
- La pantalla de captura muestra preview de cámara en vivo.
- El botón "Capturar" toma una foto real.
- La foto se persiste (en memoria por ahora) y se puede ver en preview.
🟡 T-409: Implementar ViewModel + StateFlow en 2-3 pantallas¶
Por qué: la app no tiene ViewModels. Todo el estado vive en mutableStateOf dentro de Composables. Esto bloquea tests unitarios y rompe con la arquitectura de Android recomendada.
Acción:
- Agregar
androidx.lifecycle:lifecycle-viewmodel-composealibs.versions.toml. - Crear
DashboardViewModel,ReportesViewModel,KycViewModel. - Refactorizar las 3 pantallas para consumir el VM.
- Patrón de ejemplo:
StateFlow<UiState>consealed class UiState { Loading, Success, Error }.
Criterios de aceptación:
- Las 3 pantallas usan
viewModel()para su estado. - El estado sobrevive a cambios de configuración (rotación).
- Hay un test unitario del ViewModel.
🟡 T-410: Tests unitarios para LockerCodeGenerator¶
Por qué: el algoritmo Mod-10 está implementado pero no validado por tests.
Archivo a crear: app/src/test/java/com/example/islabox/core/util/LockerCodeGeneratorTest.kt
Casos de prueba:
calculateCheckDigit(1042) == 8format(1042) == "CP-001042-8"validate("CP-001042-8") == Validvalidate("CP-001042-7") == InvalidCheckDigitvalidate("cp0010428") == Valid(normalización)validate("CP-001042") == Invalid(longitud)validate("XX-001042-8") == InvalidPrefix
Criterios de aceptación:
- Los 7 casos pasan.
- La cobertura de
LockerCodeGeneratores 100%.
🟡 T-411: Limpieza de archivos huérfanos¶
Por qué: T-204 y T-205 quedaron como "resolución parcial" porque la doc no confirmó la eliminación física.
Verificar y eliminar:
app/src/main/java/com/example/islabox/ui/screens/main/ReporteScreen.ktapp/src/main/java/com/example/islabox/domain/model/SampleModel.ktapp/src/main/java/com/example/islabox/domain/repository/SampleRepository.kt(si existe)
Criterios de aceptación:
-
git statusno muestra los archivos. - El proyecto compila.
- No hay imports rotos.
🟢 T-412: Cargar la fuente Inter desde res/font/¶
Por qué: Type.kt define FontFamily.SansSerif como placeholder. La doc pide Inter.
Archivos a crear:
app/src/main/res/font/inter_regular.ttfapp/src/main/res/font/inter_semibold.ttfapp/src/main/res/font/inter_bold.ttfapp/src/main/res/font/inter_extrabold.ttf
Criterios de aceptación:
- La app usa Inter en todas las pantallas.
--Estado al 2026-06-07: ✅ Resuelto y obsoleta. AndroidManifest.xml no declara package= (es obsoleto desde AGP 7+); el namespace = "com.islabox.app" del build.gradle.kts define el R class y el applicationId. Los import com.islabox.app.R en los archivos .kt funcionan correctamente. La inconsistencia reportada ya no existe. Tarea eliminada del backlog.**
Por qué (motivo original): app/build.gradle.kts define namespace = "com.islabox.app" pero AndroidManifest.xml declara <activity android:name="com.example.islabox.MainActivity">. Esto causa warnings en build y bloquea el correcto funcionamiento de com.islabox.app.R que ya usan los archivos (visto en RegisterScreen.kt línea 17: import com.islabox.app.R).
Archivos a modificar:
app/src/main/AndroidManifest.xml— cambiarandroid:namede la activity.
Cambio:
<activity
android:name=".MainActivity"
...>
Criterios de aceptación:
- Build sin warnings de
package. ✅ -
com.islabox.app.Rresuelve en todos los archivos. ✅ android:name=".MainActivity" ...> ``` Estado al 2026-06-07: ✅ Resuelto**. User.kttienecountryCode: String = "US"(no editable, ver constructor).CurrentUser.ktestablececountryCode = "US".RegisterScreen.kttieneavailableCountries = listOf(countries[0])(bloqueado a +1) yphoneIsValid = phone.length == 10 && isUS.- Mensaje de error
R.string.origin_rule_error: "IslaBox está disponible solo para usuarios en EE.UU. Si quieres recibir un paquete, pídele a quien te envía que se registre."
Por qué: la Regla de origen del usuario establece que solo se registran personas en EE.UU. La app actualmente permite el país con un dropdown pero la implementación debe:
- (a) En el registro: el campo
phonedebe ser +1 (EE.UU., 10 dígitos). El dropdown puede seguir existiendo pero si selecciona otro país, mostrar error. - (b) En el modelo
User: agregarcountryCode: String = "US"no editable. - (c) Mensaje de error UX: "IslaBox está disponible solo para usuarios en EE.UU. Si quieres recibir un paquete, pídele a quien te envía que se registre."
Archivos a modificar:
app/src/main/java/com/example/islabox/domain/model/User.kt— agregarcountryCode.app/src/main/java/com/example/islabox/ui/screens/auth/RegisterScreen.kt— validar.app/src/main/java/com/example/islabox/data/local/CurrentUser.kt— agregarcountryCode = "US".
Criterios de aceptación:
-
User.countryCodeesUSy no es editable. ✅ - El registro rechaza teléfonos que no sean +1 con 10 dígitos. ✅
-
El mensaje de error es claro y amable. ✅
-
app/src/main/java/com/example/islabox/domain/model/User.kt— agregarcountryCode. app/src/main/java/com/example/islabox/ui/screens/auth/RegisterScreen.kt— validar.app/src/main/java/com/example/islabox/data/local/CurrentUser.kt— agregarcountryCode = "US".
Criterios de aceptación:
-
User.countryCodeesUSy no es editable. - El registro rechaza teléfonos que no sean +1 con 10 dígitos.
- El mensaje de error es claro y amable.
🟠 T-415: Componente IslaPhoneFieldInternational para destinatarios¶
Por qué: el campo phone de Contact/Recipient debe aceptar +53 (Cuba, 8 dígitos) además de +1 (EE.UU., 10 dígitos). El IslaPhoneField actual solo soporta +1.
Archivos a crear / modificar:
app/src/main/java/com/example/islabox/ui/components/common/IslaTextFields.kt— refactorizarIslaPhoneFieldo crear varianteIslaPhoneFieldInternationalparametrizable porrecipientCountries: List<Country>.
Criterios de aceptación:
- El campo
phonedeContact/Recipientacepta +53 y +1. - El placeholder y
maxLengthse adaptan al país seleccionado. - Al guardar, se almacena en formato E.164 (
+53XXXXXXXXo+1XXXXXXXXXX).
🟠 T-416: DestinatarioSelector debe permitir alta y edición¶
Por qué: el componente muestra un card con el destinatario pero no permite agregar uno nuevo ni editar los existentes. El usuario queda sin forma de gestionar sus destinatarios en Cuba.
Archivos a modificar:
app/src/main/java/com/example/islabox/ui/components/reporte/DestinatarioSelector.kt- Crear
app/src/main/java/com/example/islabox/ui/screens/main/ContactosScreen.kt(gestión completa).
Criterios de aceptación:
- Desde el formulario de reporte, el usuario puede tocar "+ Agregar destinatario".
- Se abre un bottom sheet o pantalla de alta con nombre, CI, dirección, provincia, municipio, teléfono.
- El nuevo destinatario se guarda en
FakeDataSource.recipientsy queda seleccionable. Estado al 2026-06-07: ✅ Resuelto**.AttentionSectionmuestra los 7AttentionTypecon navegación contextual.FakeDataSource.attentionItemstiene los datos de muestra.
Por qué: la doc funcional define 7 tipos de elementos que requieren acción: KYC rechazado, paquete sin prealerta, almacenaje por vencer, pago pendiente, aduana requiere información, servicio completado, producto restringido. La app no tiene esta sección.
Criterios de aceptación:
- El dashboard muestra esta sección solo cuando hay elementos. ✅
- Cada item tiene CTA directo a la pantalla relevante (KYC, Reportes, Cotización, etc.). ✅l guardar un reporte, no se persiste el
senderId. Falta la conexión con elpurchase_report_iddel modeloReporte.remitenteId.
Criterios de aceptación:
- Al guardar un reporte,
Reporte.remitenteIdqueda con el id del usuario actual. - Si hay más remitentes guardados (Fase 2), se muestran como opción.
🟠 T-418: Sección "Requiere tu atención" en Dashboard¶
Por qué: la doc funcional define 7 tipos de elementos que requieren acción: KYC rechazado, paquete sin prealerta, almacenaje por vencer, pago pendiente, aduana requiere información, servicio completado, producto restringido. La app no tiene esta sección.
Estado al 2026-06-07: ⚠️ Pantalla creada, link de acceso pendiente. AduanaInfoScreen.kt está implementada con 6 secciones y fecha de norma 2026-06-04. La ruta Screen.AduanaInfo existe en NavGraph.kt pero ningún botón de la app navega hacia ella**. Falta agregar el link en GuiaScreen (T-419-link en estado-actual.md).
Por qué: la doc pide que el usuario pueda ver reglas de aduana, límites, exenciones y glosario. No existe.
Acción:
- Crear
app/src/main/java/com/example/islabox/ui/screens/guia/AduanaInfoScreen.kt. - Mostrar las 6 secciones definidas en
datos/aduana.md.
Criterios de aceptación:
- Pantalla creada. ✅
- Muestra fecha de actualización de la norma. ✅
- El usuario accede desde la sección "Guía" del dashboard. ❌ (T-419-link) reglas de aduana, límites, exenciones y glosario. No existe.
Acción:
- Crear
app/src/main/java/com/example/islabox/ui/screens/guia/AduanaInfoScreen.kt. - Mostrar las 6 secciones definidas en
datos/aduana.md.
Criterios de aceptación:
- El usuario accede desde la sección "Guía" del dashboard.
- Muestra fecha de actualización de la norma.
🟡 T-420: Drawable de los logos en formato vectorial¶
Por qué: T-001 quedó con PNG. Aunque funcional, los PNG pesan más y no escalan bien. Migrar a VectorDrawable es preferible.
Acción: convertir los 4 PNG a XML vectoriales y actualizar IslaImages.kt.
🟢 T-421: Eliminar colores hardcodeados en componentes¶
Por qué: la doc tema-diseno.md señala 3 grises diferentes hardcodeados (0xFFF1F4F9, 0xFFF0F4F8, 0xFFF0F0F5) y 2 rojos (0xFFBB0016 paleta, 0xFFD32F2F Cerrar Sesión). Unificar a tokens del theme.
Archivos a revisar: cualquier .kt con literales Color(0xFF...).
🆕 Tareas nuevas — auditoría de flujos 2026-06-07¶
Alcance del Bloque D: el objetivo es avanzar en la maquetación visual de la APK sin backend ni autenticación real. Las validaciones que se implementen son solo de cliente (regex, longitud, formato) para mejorar la UX; ninguna tarea de este bloque pretende reemplazar lógica de servidor (login real, cobro real, conciliación real, etc.). Donde un flujo completo dependa de backend, la tarea se limita a dejar la UI navegable y mostrar datos mockeados de
FakeDataSource.
Estas tareas surgieron del análisis del código y de los flujos de cara al usuario final. Ver detalle completo en informe_flujo.md.
🔴 T-422: ReporteDetalle debe enlazar con QuoteScreen usando datos mockeados coherentes¶
Por qué: ReporteDetalleScreen.kt:360 usa onPayClick = { onPayClick("QUO-001") } con un id hardcodeado. Independientemente del paquete, siempre abre QuoteScreen con la cotización de muestra. La UI debe enlazar a una Quote específica del FakeDataSource que sea coherente con el Reporte que el usuario está viendo.
Archivos a modificar:
app/src/main/java/com/example/islabox/data/local/FakeDataSource.kt— agregar helperfindQuoteForReporte(reporteId: String): Quote?que devuelva la cotización asociada al reporte onullsi no hay.app/src/main/java/com/example/islabox/ui/screens/reporte/ReporteDetalleScreen.kt— usar el helper enonPayClickpara pasar el id real.- Agregar cotizaciones de muestra en
FakeDataSource.quotespara al menos los reportes conpackageStatus = LISTO_PARA_ENVIARoCONSOLIDADO.
Alcance MVP visual (sin backend): no se pretende que el pago funcione, solo que la navegación llegue a una pantalla de cotización con datos coherentes.
Criterios de aceptación:
- Cada reporte con
packageStatus = LISTO_PARA_ENVIARoCONSOLIDADOmuestra suQuoteespecífica al tocar "Pagar Envío". - Si el reporte no tiene cotización, el botón muestra un toast "No hay cotización disponible" en vez de navegar.
-
QuoteScreenmuestra "Cotización no encontrada" si el id no existe enFakeDataSource.quotes.
🔴 T-423: PerfilScreen debe tener navegación a sub-pantallas (maquetación, sin backend)¶
Por qué: 7 de 8 items del menú de PerfilScreen tienen onClick vacío o /* TODO */. Items afectados: "Mi Información", "Direcciones", "Métodos de Pago", "Notificaciones", "Ayuda y Soporte", "Privacidad", y el botón "Cerrar Sesión". El usuario ve un menú profesional pero los items no navegan a ningún lado.
Archivos a modificar / crear:
app/src/main/java/com/example/islabox/ui/screens/main/PerfilScreen.kt— cablearonClicken los items para que naveguen a pantallas (existentes o nuevas) en lugar de quedar vacíos.- Reusar
ContactosScreen(ya existe) para "Direcciones". - Crear
EditProfileScreen.kt(UI con campos y validaciones de cliente, sin llamada a backend). - Crear
PaymentMethodsScreen.kt(UI con lista de tarjetas hardcodeadas enFakeDataSource, sin integrar Stripe). - "Cerrar Sesión" debe navegar a
Screen.Welcome(sin limpiar tokens, porque todavía no hay sesión real). - Items sin pantalla: mostrar un toast "Próximamente" o
ComingSoonScreenplaceholder.
Alcance MVP visual (sin backend): las pantallas se ven completas, navegan correctamente, muestran datos de FakeDataSource, pero ninguna llama a un endpoint.
Criterios de aceptación:
- "Mi Información" navega a
EditProfileScreencon formulario editable. - "Cerrar Sesión" navega a
Screen.Welcome(sin lógica de tokens). - "Direcciones" navega a
ContactosScreen. - "Métodos de Pago" navega a
PaymentMethodsScreencon lista mockeada. - Los items restantes ("Notificaciones", "Ayuda y Soporte", "Privacidad") muestran un toast "Próximamente" o navegan a
ComingSoonScreen.
🟠 T-424: ReportActionBanner debe llevar a ReporteForm, no a Reportes (maquetación)¶
Por qué: DashboardScreen.kt:199 hace que el banner "Reportar compra" navegue a la lista Reportes en vez de al formulario. El usuario tiene que tocar el banner, ver la lista, y volver a tocar el FAB. Doble fricción.
Archivos a modificar:
app/src/main/java/com/example/islabox/ui/screens/main/DashboardScreen.kt— cambiaronClickanavController.navigate(Screen.Dashboard.ReporteForm).
Alcance MVP visual (sin backend): solo se ajusta la navegación. El handler de envío del formulario sigue mockeado (T-201).
Criterios de aceptación:
- El banner "Reportar compra" del dashboard abre directamente el formulario.
🟠 T-425: ReporteDetalle debe mostrar nombre del destinatario (no el ID)¶
Por qué: ReporteDetalleScreen.kt:234 muestra reporte.destinatarioId ?: "No asignado". El usuario ve CONT-001 en vez de "Juan Pérez". La doc pide ver el nombre del destinatario.
Archivos a modificar:
app/src/main/java/com/example/islabox/ui/screens/reporte/ReporteDetalleScreen.kt— hacer join conFakeDataSource.recipients(o el repository) y mostrarContact.name.
Alcance MVP visual (sin backend): solo UI. El join se hace contra la lista en memoria de FakeDataSource.recipients.
Criterios de aceptación:
- El destinatario se muestra con su nombre completo (
Contact.name) en vez del id (CONT-001). - Si el destinatario no existe en
FakeDataSource.recipients, se muestra "Destinatario no encontrado" en vez del id crudo.
🔴 T-426: LoginScreen debe validar formato en cliente (sin backend)¶
Por qué: LoginScreen.kt:90-91 navega a Main con cualquier toque del botón, incluso con campos vacíos. Aunque no hay backend para validar credenciales reales, se debe mejorar la UX: deshabilitar el botón mientras el email no tenga formato válido o la contraseña esté vacía.
Archivos a modificar:
app/src/main/java/com/example/islabox/ui/screens/auth/LoginScreen.kt— agregar validación inline (email regex, password no vacía) y deshabilitar botón si inválido. Mostrar errores inline.
Alcance MVP visual (sin backend): la validación es solo de formato en cliente. No se pretende validar credenciales reales. El botón navega a Main cuando ambos campos cumplen formato, simulando el login exitoso (mismo comportamiento actual).
Criterios de aceptación:
- El botón "Entrar" se deshabilita si el email no tiene formato válido o la contraseña está vacía.
- Errores inline visibles en tiempo real (sin esperar al tap).
- El flujo visual de "login -> dashboard" sigue funcionando para demos (sin crash).
🟠 T-427: RegisterScreen debe validar email y requisitos de contraseña (sin backend)¶
Por qué: RegisterScreen valida origen US y coincidencia de contraseñas, pero no valida formato de email ni requisitos de contraseña (longitud, dígitos, mayúsculas). El botón se habilita con isFormValid = firstName.isNotEmpty() && ... && passwordsMatch.
Archivos a modificar:
app/src/main/java/com/example/islabox/ui/screens/auth/RegisterScreen.kt— agregarvalidateEmail(email)(regex) yvalidatePassword(password)(mín. 8 chars, 1 mayúscula, 1 dígito) con errores inline. Agregar checkbox de términos obligatorio.
Alcance MVP visual (sin backend): la validación es solo de formato en cliente. No se pretende crear el usuario en un servidor. El handler onRegisterClick se mantiene navegando a Main (mock).
Criterios de aceptación:
- Email inválido muestra error inline y deshabilita el botón.
- Contraseña con menos de 8 caracteres muestra errodeben navegar a pantallas (sin backend)
Por qué: ReporteDetalleScreen.kt:282 tiene // TODO: Otras acciones para "Solicitar reempaque", "Agregar a consolidación" y "Enviar solo". Los 3 botones se muestran pero no hacen nada.
Archivos a modificar:
app/src/main/java/com/example/islabox/ui/screens/reporte/ReporteDetalleScreen.kt— agregaronRequestRepackyonAddToConsolidationcomo parámetros y conectarlos enNavGraph.app/src/main/java/com/example/islabox/ui/navigation/NavGraph.kt— registrar ruta paraRequestRepack(similar aRequestInspection).- Conectar "Enviar solo" con navegación a
QuoteScreenusando el helper de T-422.
Alcance MVP visual (sin backend): los botones navegan a sus pantallas, pero las pantallas agregan a FakeDataSource (no llaman a endpoints).
Criterios de aceptación:
- "Solicitar reempaque" navega a la pantalla de solicitud de reempaque.
- "Agregar a consolidación" abre
ConsolidationCreateScreencon el paquete preseleccionado. -
"Enviar solo" navega a
QuoteScreencon la cotización del paquete (helper de T-422) -
app/src/main/java/com/example/islabox/ui/screens/reporte/ReporteDetalleScreen.kt— agregaronRequestRepackyonAddToConsolidationcomo parámetros y conectarlos enNavGraph. app/src/main/java/com/example/islabox/ui/navigation/NavGraph.kt— registrar ruta paraRequestRepack(similar aRequestInspection).- Conectar "Enviar solo" con la creación de un
Shipmentindividual (sin consolidación) y navegación aQuoteScreen.
Criterios de aceptación:
- "Solicitar reempaque" navega a la pantalla de solicitud de reempaque.
- "Agregar a consolidación" abre
ConsolidationCreateScreencon el paquete preseleccionado. - "Enviar solo" genera una cotización individual y navega a
QuoteScreen.
🟡 T-429: Notificaciones demo con banner "Demo" en MVP¶
Por qué: FakeDataSource.notifications tiene 12 notificaciones estáticas (subiste de nivel, crédito, etc.) que la NotificationsScreen muestra como si fueran del usuario real. Riesgo de confusión en demo con stakeholders.
Archivos a modificar:
app/src/main/java/com/example/islabox/ui/screens/main/NotificationsScreen.kt— agregar un banner superior "Datos de demostración" mientras no haya backend.
Alcance MVP visual (sin backend): solo UI. Las notificaciones son estáticas, no se generan por eventos.
Criterios de aceptación:
- La pantalla de notificaciones muestra un banner amarillo "Estás viendo datos de demostración" en MVP.
- El banner desaparece cuando se conecte el backend real.
Resumen de avance — actualizado al 2026-06-07 (verificado contra código)¶
| Sprint / bloque | Tareas | ✅ Completadas | ❌ Abiertas | % Avance |
|---|---|---|---|---|
| 0 — Crash fixes | 3 | 3 | 0 | 100% |
| 1 — Datos y FakeDataSource | 6 | 6 | 0 | 100% |
| 2 — Pantallas Auth/KYC | 6 | 6 | 0 | 100% |
| 3 — Componentes y validaciones | 5 | 5 | 0 | 100% |
| 4 — Envíos y paquetes | 2 | 2 | 0 | 100% |
| 5 — Servicios | 3 | 3 | 0 | 100% |
| Tareas transversales (ProGuard, Java 17, T-413 obsoleta, T-414) | 4 | 4 | 0 | 100% |
| Bloque B — Vigentes (T-417, T-501-persist) | 2 | 0 | 2 | 0% |
| Bloque C — Nuevas 2026-06-04 (T-419, T-423, T-425, T-206b, T-405, T-427, T-428, T-429, T-431) | 9 | 5 | 4 | 56% |
| Bloque D — Maquetación visual sin backend (T-422-persist, T-422-onPayConsolidation, T-433, T-434, etc.) | 8 | 4 | 4 | 50% |
| Total | 48 | 37 (77%) | 10 (21%) | 77% |
Nota: el conteo se redujo de 46 a 48 porque la auditoría del 2026-06-07 agregó T-431 (captura de ZIP en KYC) y T-501-persist (persistencia del nuevo
ServiceRequest). T-413 se marca como obsoleta. T-414 se movió a "transversales" ya resuelta.
Veredicto: la APK está 77% completa sobre el plan original. El 21% restante son, en su mayoría, tareas de persistencia de formularios (los handlers de submit no escriben a FakeDataSource), validaciones de cliente (email, password) y navegación de Perfil (7/8 items sin onClick). No son bloqueantes para una demo de maquetación visual; son necesarias para que la app sea coherente de extremo a extremo.
Tareas críticas pendientes (orden de prioridad):
- T-417: persistir nuevo
ReporteenFakeDataSource. - T-501-persist: persistir nuevo
ServiceRequest. - T-405: alinear enums con nombres oficiales snake_case en español.
- T-206b: actualizar
AppSettingsa los valores de la doc (15 días, $0.50, 3 días). - T-423: navegación de sub-pantallas de
PerfilScreen(7/8 items). - T-425: mostrar nombre del destinatario en
ReporteDetalleen vez del ID. - T-419-link: link a
AduanaInfodesde la nav. - T-427/T-428: validaciones de email y password en
RegisterScreen. - T-429: banner "Demo" en
NotificationsScreen. - T-431: captura de ZIP en
KycResidenceScreen.