LUCIANO CARRIZO
My School
Todos los proyectos
Finalizado

My School

App mobile (Expo + React Native) para organizar la cursada: materias, actividades y tareas en una jerarquía de tres niveles, más un calendario de vencimientos. Funciona 100% local, sin backend ni cuentas. Se diseñó entera antes de programarla: 26 wireframes HTML commiteados primero y 11 fases numeradas que los implementaron una por una.

ExpoReactTypeScript
Resumen

Una app para ordenar la cursada, entera en el teléfono

My School es una app mobile de organización académica para estudiantes: cargás tus materias, lo que hay que entregar en cada una y las tareas que componen cada entrega, y la app te muestra qué vence y cuándo. La estructura es una jerarquía de tres niveles —Materia → Actividad (con Proyecto opcional que agrupa) → Tarea— más una vista de calendario que junta todo lo que tiene fecha.

Está construida con Expo 54 y Expo Router 6 sobre React Native 0.81 y React 19, en TypeScript 5.9, con Zustand para el estado y un sistema de theming propio con soporte claro/oscuro e i18n español/inglés. Corre también en el navegador vía react-native-web, que es de donde salen las capturas de esta página.

Funciona 100% local: no hay backend, ni cuentas, ni sincronización entre dispositivos. Es un dato del alcance, no una promesa pendiente — todo lo que la app guarda vive en el teléfono.

Es un proyecto 100% propio: 32 commits, todos míos, sin fork ni upstream que acreditar, en una ventana de 13 días (2026-04-22 a 2026-05-05).

El proceso

26 wireframes HTML antes de escribir una línea de React Native

Esta es la parte que más define al proyecto, y se puede verificar sin creerme nada: está en el orden de los commits. Los primeros seis commits del repo no tienen una línea de React Native. Son la carpeta design/: 26 wireframes HTML (design/views/*.html con su design/css/wireframe.css), escritos a mano, uno por pantalla de la app. Recién después aparece chore: initialize Expo 54 project setup (Fase 0).

De ahí en adelante el trabajo va por fases numeradas, y cada fase implementa una parte de lo que ya estaba dibujado:

FaseQué entra
Fase 0Setup del proyecto Expo 54
Fase 1Tokens y sistema de theming
Fase 2Capa de datos
Fase 3Navegación
Fase 4Materias (Course)
Fases 5-7Tareas, Actividades y Proyectos
Fase 8Calendario
Fase 9Búsqueda
Fase 10Settings
Fase 11Polish

Después de la Fase 11 vienen los commits de fixes y pulido, y la internacionalización entra al final, en su propio commit dedicado.

Lo que este orden compra es concreto: la Fase 1 puede arrancar por los tokens de diseño porque las 26 pantallas ya existían en HTML y se sabía qué colores, tipografías y espaciados hacían falta. La Fase 3 puede armar la navegación porque el mapa de pantallas ya estaba completo, no se iba descubriendo. Y las fases 4 a 7 son verticales de producto —una entidad entera cada una— en vez de “hacer todas las pantallas a medias y volver”.

El costo también es real: diseñar 26 pantallas antes de programar es trabajo que no produce app durante seis commits, y compromete decisiones de UI antes de haber tocado un dispositivo. En este proyecto salió bien porque el alcance estaba acotado y era para un usuario conocido; no es una receta que se pueda mudar tal cual a un producto con requisitos en movimiento.

La jerarquía de datos

Tres niveles, y un cuarto opcional que agrupa

El modelo es lo que hace que la app sirva para una cursada real y no sea una lista de tareas con un nombre bonito. Está documentado en docs/architecture.md y declarado en src/types/entities.ts:

Course (Materia)
└── Project (opcional — agrupa activities relacionadas)
    └── Activity
        └── Task
└── Activity (suelta, sin project)
    └── Task
└── Task (suelta, sin activity)

La clave está en los “opcional” y “suelta”: ningún nivel intermedio es obligatorio. Una tarea puede colgar directo de la materia sin inventarle una actividad contenedora, y una actividad puede existir sin proyecto. Un modelo rígido de cuatro niveles obligatorios te fuerza a crear entidades vacías solo para llegar al nivel donde querés anotar algo — que es exactamente el momento en el que alguien deja de usar la app.

Esa flexibilidad obliga a definir reglas de borrado que no son las de un árbol común, y están escritas:

01

Borrar una materia borra en cascada

El Course es el único nivel que arrastra todo lo que cuelga de él: si la materia se va, se van sus proyectos, actividades y tareas.

02

Borrar un proyecto o una actividad NO borra a sus hijos

Los hijos quedan sueltos bajo el Course, que es el nivel que sí existe siempre. Reorganizar no puede costarte datos.

03

El progreso se calcula, no se carga

El avance de un Project es tasks completadas sobre tasks totales — un número derivado, sin campo que pueda quedar desactualizado.

04

Al calendario solo llega lo que tiene dueDate

Sin fecha de vencimiento, un ítem existe en su materia pero no ocupa lugar en el calendario.

Detalle de la materia Programación III: profesor, descripción, horarios, y la lista de actividades pendientes con barra de progreso, más la sección de completadas
El detalle de una materia: pendientes con su barra de progreso calculada arriba, completadas abajo.
El producto

Materias, actividades y calendario, funcionando

Las capturas son de la app real corriendo en navegador con los datos de prueba que genera el propio botón de Settings. Son las tres vistas principales, una por pestaña.

Pantalla Mis Materias: buscador y tarjetas de Matemática II, Programación III, Física e Inglés Técnico, cada una con profesor y contadores de pendientes y completadas
Materias: cada tarjeta trae su profesor y cuántas actividades tiene pendientes y completadas.
Pantalla Actividades con sub-pestañas Tasks, Actividades y Projects, buscador, filtros por materia y una lista de 16 tareas pendientes etiquetadas con su materia, su actividad y su fecha de vencimiento
Actividades: sub-pestañas por nivel de la jerarquía, filtro por materia y búsqueda global.
Calendario en vista Mes, julio 2026, con el día actual resaltado y marcadores de color bajo los días que tienen vencimientos
Calendario: vistas día, semana y mes, con marcadores en los días que tienen vencimientos.

La pantalla de actividades es donde se ve la jerarquía de la zona anterior puesta a trabajar: las sub-pestañas Tasks / Actividades / Projects son los tres niveles, y el filtro por materia los cruza con el nivel de arriba. Cada tarea muestra a qué materia y a qué actividad pertenece, así que la lista plana no pierde el contexto que da el árbol.

Arquitectura

Una capa de repositorios sobre un storage que cambia según la plataforma

El acceso a datos no está desparramado por los componentes: hay una capa de repositorios con interfaces en src/repositories/. Una interfaz genérica define el contrato y cada entidad tiene la suya, separada de su implementación concreta:

src/repositories/
  IRepository.ts          ← genérica: getAll / getById / create / update / delete
  ICourseRepository.ts    IActivityRepository.ts
  IProjectRepository.ts   ITaskRepository.ts
  courseRepository.ts     activityRepository.ts   ← implementaciones
  projectRepository.ts    taskRepository.ts

Debajo hay una sola implementación, y ahí está el detalle que importa: el almacenamiento cambia según la plataforma. src/storage/storageAdapter.ts elige por Platform.OS entre expo-secure-store en iOS y Android y localStorage en web, así que la misma app corre en el teléfono y en el navegador sin que el resto del código se entere. Es lo que hace posible que estas capturas existan.

Lo que hay que decir con la misma claridad: no hay una base de datos real. No hay SQLite ni ningún motor detrás — es persistencia de estado (Zustand con su middleware de persistencia, apoyado en ese adapter), no una capa de datos. Funciona para el alcance de la app y no pretende más que eso.

El resto sigue el mismo corte: app/ —las rutas de Expo Router, con su grupo (tabs) y sus rutas dinámicas [id].tsx— queda delgado, y la lógica vive en src/ repartida en components/, stores/, repositories/, theme/, hooks/, i18n/ y utils/.

Cierre

13 días, sin tests y sin CI, con un pendiente a la vista

No hay tests y no hay CI

Cero archivos de test en el repo y ningún workflow de GitHub Actions: no existe .github/. Lo digo derecho porque es verdad y porque no es de lo que trata este caso: acá lo que se demuestra es el proceso de diseño→código y el producto que salió de él, no una disciplina de testing que este proyecto no tuvo. En 13 días entró la app entera y quedó afuera todo lo automatizado.

Decisión

El TODO.md sigue con un ítem abierto

Queda un pendiente anotado: mostrar en la vista semana del calendario los proyectos que tienen dueDate. Lo dejo escrito en vez de borrarlo, y aun así el proyecto figura como finalizado: el MVP está cerrado y usable, y ese detalle no bloquea nada de lo que la app hace hoy.

Hay una imprecisión heredada que corrijo acá: la descripción del repo en GitHub dice “React Navigation”, y la app en realidad usa Expo Router — React Navigation aparece como dependencia transitiva, no como la API que se programa. También hay un docs/project.md de arranque que quedó desactualizado (todavía lista como “a confirmar” cosas que el código resolvió hace 32 commits); lo dejo como lo que es, evidencia de que hubo planificación previa, no como fuente del stack.

El proyecto está finalizado en el sentido más literal: 32 commits propios, 13 días, una app completa con su jerarquía de datos, su calendario, su búsqueda, sus dos idiomas y sus dos temas. Lo que me llevo es la parte del principio: dibujar las 26 pantallas antes de escribir código es lo que hizo que las 11 fases fueran implementación y no descubrimiento.

Siguiente paso

El caso muestra el código. Hablemos de lo que sigue.

My School está documentado end-to-end: arquitectura, decisiones y lo que quedó pendiente. Si tenés preguntas sobre el enfoque, escribime.

Hablemos

o directamente → LuchoC.dev@gmail.com