Conversation
…panel web La demo navegable muestra el flujo del producto, pero corre entera en el cliente. Esto es la aplicacion real: una sola app con dos modos, igual que en el MVP. Motor de bloqueo (core/motor): Port de evaluar() de assets/app.js, pero puro y sincronico. Lo llama el VpnService una vez por consulta DNS, asi que no puede tocar disco ni red: quien lo construye ya le pasa las listas resueltas. Por eso se testea con JUnit comun, sin emulador. 10 tests, incluido el caso de que nobet365.bet no cae por la regla bet365.bet sino por el TLD. Las tres capas, en orden de alcance: 1. VpnService. Levanta una interfaz tun dentro del propio equipo y se declara unico DNS. No hay servidor del otro lado. Responde NXDOMAIN a lo bloqueado y reenvia el resto a upstream. Es la unica capa que alcanza a todas las apps. Al tun solo se enruta el trafico hacia el DNS virtual: la app ve nombres de dominio, no contenido, y eso lo garantiza la ruta, no el README. 2. AccessibilityService. Cubre exactamente los huecos de la capa 1: DoH, WebView dentro de otra app, y conexiones con el dominio ya resuelto. Limitado por lista de paquetes y por id de recurso, sin flagRetrieveInteractiveWindows. 3. DeviceAdminReceiver. No bloquea nada: impide desinstalar la app, que es como se apagan las otras dos en dos toques. Pide una sola politica, watch-login. Nada de wipe remoto ni politicas de contrasenia. Persistencia (Room + DataStore): se guarda dominio, regla, capa y momento. No URL completa, ni titulo de pagina, ni capturas. Es el historial de navegacion de un chico. El backup automatico de Android esta excluido y la retencion es de 90 dias. Documentacion: - ARQUITECTURA.md: por que el producto esta partido en tres piezas. - INSTALACION.md: los dos telefonos paso a paso, que ve y que no ve la app, y las cinco pruebas de verificacion. - panel/README.md: el panel web con login, modelo de datos y reglas de acceso. Verificado: assembleDebug y testDebugUnitTest en verde, 10/10 tests, APK de 11 MB. Falta el backend, la vinculacion real de los dos equipos y el onboarding de modo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Antes era un solo APK con dos modos elegidos en el onboarding. Ahora son dos aplicaciones instalables distintas, generadas con product flavors de Gradle desde el mismo codebase. La razon de fondo no es organizativa, es de permisos. El VpnService, el AccessibilityService y el DeviceAdminReceiver se declaran en app/src/dispositivo/AndroidManifest.xml, asi que el APK del adulto no los lleva. Verificado con aapt2 sobre los binarios compilados: control declara ProtegeApp y MainActivity, nada mas; dispositivo declara ademas los cinco componentes de la proteccion. Un adulto que instala la app de control nunca ve el dialogo de VPN ni la advertencia de accesibilidad, porque su APK no puede dispararlos. Reparto de fuentes: - app/src/main motor, Room, DataStore, notificaciones, tema - app/src/control MainActivity propia, PanelResponsable, CodigoVinculacion - app/src/dispositivo MainActivity propia, y todo protegido/** Las dos MainActivity comparten nombre de clase a proposito: el manifiesto compartido declara .MainActivity y cada flavor compila la suya. Por eso Notificaciones dejo de nombrar la clase y ahora pide el launcher del propio paquete con getLaunchIntentForPackage: codigo compartido que no se ata a un flavor. Front nuevo del adulto (PanelResponsable): alertas sin leer, lista personalizada con alta y baja, generacion del codigo de vinculacion y las lineas de ayuda. Sin backend no hay dispositivos que listar, asi que la pantalla explica que falta en vez de mostrar una tarjeta vacia. CodigoVinculacion usa SecureRandom: seis digitos alcanzan porque vence en 10 minutos y se quema al primer uso, pero un codigo predecible seria un equipo ajeno vinculado a la cuenta de otro. En la app del equipo protegido se sumo el aviso de supervision en pantalla, que no se puede ocultar. Documentacion actualizada: README, ARQUITECTURA.md e INSTALACION.md decian lo contrario. La guia de instalacion ahora distingue que APK va en cada telefono y usa como senal el hecho de que la app del adulto nunca pide VPN. Verificado: assembleDebug genera los dos APK, 10/10 tests en cada flavor. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Cambio de arquitectura: dos aplicaciones en vez de unaEl PR arrancaba con un solo APK de dos modos, siguiendo lo que decía el README. Ahora son dos aplicaciones instalables distintas, generadas con product flavors de Gradle desde el mismo codebase.
La razón de fondo es de permisos, no de organización. Verificado con Un adulto que instala la app de control nunca ve el diálogo de VPN ni la advertencia de accesibilidad, porque su APK no declara los servicios que los disparan. Eso importa para la adopción y para la revisión de Play, donde cada aplicación se evalúa por lo que realmente declara. Front nuevo del adulto
Un detalle que puede sorprender al revisarLas dos VerificaciónREADME, 🤖 Generated with Claude Code |
La demo navegable muestra el flujo completo del producto, pero corre entera en el cliente. Esto es la aplicación real: una sola app con dos modos, tal como quedó definido en el MVP.
Las tres capas
VpnServiceAccessibilityServiceDeviceAdminReceiverLa capa 2 cubre exactamente los huecos de la capa 1: DNS sobre HTTPS, WebView dentro de otra app, y conexiones con el dominio ya resuelto. No es redundancia.
Decisiones que vale la pena revisar
El motor es puro y sincrónico. Lo llama el
VpnServiceuna vez por consulta DNS, así que no puede tocar disco ni red: quien lo construye ya le pasa las listas resueltas, y los servicios se quedan con la última versión en un campo@Volatile. Por eso se testea con JUnit común, sin emulador.Al tun solo se enruta el tráfico hacia el DNS virtual (
addRoute(DNS_VIRTUAL, 32)). La app ve nombres de dominio consultados, no contenido. Eso lo garantiza la ruta, no una promesa del README.El Device Admin pide una sola política,
watch-login. Nada de wipe remoto, bloqueo de pantalla ni políticas de contraseña. Un control parental que puede borrar el teléfono es un control parental que un día borra un teléfono.Se guarda dominio, regla, capa y momento. No URL completa, ni título de página, ni capturas. Es el historial de navegación de un chico: el mínimo que sirve para que un adulto entienda qué pasó es también el máximo que corresponde guardar. Backup automático de Android excluido, retención de 90 días.
Un solo APK y no dos. Dos aplicaciones significarían dos fichas de Play Store, dos revisiones de política y dos claves de firma para un producto que ya pide tres permisos sensibles. El costo es que el APK del equipo protegido lleva código del modo responsable que nunca ejecuta.
Documentación
ARQUITECTURA.md: por qué el producto está partido en tres piezas.INSTALACION.md: los dos teléfonos paso a paso, qué ve y qué no ve la app, y cinco pruebas de verificación. Arranca con qué hablar antes de instalar: la notificación permanente no se puede ocultar y Play exige que la supervisión sea visible.panel/README.md: el panel web con login, modelo de datos y reglas de Firestore.Verificación
./gradlew :app:assembleDebug :app:testDebugUnitTesten verde, sin warnings. JDK 17, SDK 35, AGP 8.7.3, Kotlin 2.0.21.Lo que falta
Backend (los puntos están marcados con
// BACKEND), vinculación real de los dos equipos con código de un solo uso, onboarding de selección de modo, sincronización periódica de la lista oficial conWorkManager, e implementación del panel web.🤖 Generated with Claude Code