https://github.com/code3743/todo-list
https://github.com/code3743/todo-list
Last synced: about 1 month ago
JSON representation
- Host: GitHub
- URL: https://github.com/code3743/todo-list
- Owner: code3743
- Created: 2026-05-14T01:03:23.000Z (about 2 months ago)
- Default Branch: main
- Last Pushed: 2026-05-14T16:34:58.000Z (about 2 months ago)
- Last Synced: 2026-05-14T18:29:37.919Z (about 2 months ago)
- Language: TypeScript
- Size: 20.1 MB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Todo List — Ionic + Angular + Firebase
Aplicación móvil de lista de tareas construida con Ionic, Angular y Cordova. Permite gestionar tareas y categorías con almacenamiento local o Firebase Firestore, e incluye un feature flag con Firebase Remote Config.
## Stack
- **Ionic** 8 + **Angular** 20 (standalone components)
- **Cordova** — compilación nativa Android e iOS
- **Firebase** 12 (Firestore + Remote Config)
- **Angular Signals** — gestión de estado reactivo
---
## Funcionalidades
- Agregar, completar y eliminar tareas
- Crear, editar y eliminar categorías con color
- Asignar una categoría a cada tarea
- Filtrar tareas por categoría
- **Feature flag** vía Firebase Remote Config: activa/desactiva la sección de categorías en tiempo real sin redesplegar la app
- Datasource intercambiable: `local` (localStorage) o `firebase` (Firestore) con un solo cambio en `environment.ts`
---
## Requisitos previos
- Node.js ≥ 18
- npm ≥ 9
- Ionic CLI: `npm install -g @ionic/cli`
- Cordova CLI: `npm install -g cordova`
- **Android:** Android Studio con un AVD configurado
- **iOS:** Xcode 15+ (solo macOS)
---
## Instalación
```bash
git clone https://github.com/code3743/todo-list.git
cd todo-list
npm install
```
---
## Ejecutar en web
```bash
ionic serve
```
Abre `http://localhost:8100` en el navegador.
---
## Compilar y ejecutar en iOS
```bash
ionic build
cordova run ios --emulator
```
O para abrir en Xcode y seleccionar el simulador manualmente:
```bash
ionic build
cordova prepare ios
open platforms/ios/*.xcworkspace
```
---
## Compilar y ejecutar en Android
```bash
ionic build
cordova run android --emulator
```
O para abrir en Android Studio:
```bash
ionic build
cordova prepare android
# Abre la carpeta platforms/android en Android Studio
```
---
## Configuración de Firebase
Las credenciales de Firebase están en `src/environments/environment.ts` y `environment.prod.ts`. Para usar tu propio proyecto:
1. Crea un proyecto en [Firebase Console](https://console.firebase.google.com)
2. Registra una app Web
3. Copia el `firebaseConfig` en ambos archivos de environment
4. En Firestore, crea las colecciones `tasks` y `categories`
5. En Remote Config, crea el parámetro `enable_categories` (tipo Boolean)
### Cambiar datasource
En `src/environments/environment.ts`:
```ts
datasource: 'local' // usa localStorage (default en desarrollo)
datasource: 'firebase' // usa Firestore
```
`environment.prod.ts` usa `firebase` por defecto.
### Feature flag — demostración
1. Ve a Firebase Console → **Remote Config**
2. Cambia `enable_categories` a `true` y publica
3. Recarga la app — aparece el botón de categorías y los filtros
4. Cambia a `false` y publica — la funcionalidad desaparece sin recompilar

[Demo en video](/demo.mp4)
---
## Arquitectura
```
src/app/
├── core/
│ ├── constants/ # Todas las claves y constantes centralizadas
│ ├── datasources/ # Abstracción del origen de datos
│ │ ├── tasks-datasource.ts # Contrato abstracto
│ │ ├── categories-datasource.ts
│ │ ├── local/ # Implementación localStorage
│ │ └── firebase/ # Implementación Firestore
│ ├── models/ # Interfaces Task y Category
│ └── services/ # Firebase, RemoteConfig, Storage
├── features/
│ ├── tasks/ # Componentes, servicio y pipes de tareas
│ └── categories/ # Componentes, servicio y pipes de categorías
└── shared/ # Componentes y pipes reutilizables
```
El datasource activo se inyecta en `main.ts` según `environment.datasource`, sin que los servicios de negocio (`Tasks`, `Categories`) conozcan el origen de los datos.
---
## Respuestas técnicas
### ¿Cuáles fueron los principales desafíos?
**Datasource intercambiable con Firebase y localStorage:** el reto principal fue diseñar una abstracción que soportara las operaciones síncronas del localStorage y las asíncronas de Firestore con la misma interfaz. Se resolvió con clases abstractas como tokens de inyección de Angular y métodos `Promise`-based en ambas implementaciones.
**Sincronía entre signals y operaciones async:** Angular Signals son síncronos, pero las operaciones de Firebase no. Se adoptó el patrón de *optimistic update*: la señal se actualiza inmediatamente en memoria y la operación de persistencia ocurre en paralelo, logrando una UI sin latencia percibida.
---
### ¿Qué técnicas de optimización de rendimiento aplicaste y por qué?
**`ChangeDetectionStrategy.OnPush` en todos los componentes** — Angular solo recalcula la vista cuando cambia una referencia de input, reduciendo los ciclos de detección de cambios en listas largas.
**Angular Signals** — reemplazan `BehaviorSubject` y `async pipe`. Las señales actualizan solo el nodo del DOM que depende de ese valor, sin recorrer el árbol de componentes.
**`computed()` para el filtrado de tareas** — la lista filtrada se recalcula solo cuando cambia `tasks` o `selectedCategoryId`, no en cada render. Equivale a memoización automática.
**`PreloadAllModules`** — precarga los módulos lazy en segundo plano tras el arranque inicial, eliminando el delay de navegación entre rutas.
**Optimistic updates** — la UI responde de forma inmediata sin esperar la confirmación de Firebase, haciendo la app sentir nativa.
---
### ¿Cómo aseguraste la calidad y mantenibilidad del código?
**Patrón datasource con clases abstractas** — los servicios de negocio (`Tasks`, `Categories`) dependen de contratos, no de implementaciones concretas. Agregar un nuevo backend (ej. SQLite) no requiere tocar la lógica de negocio.
**Constantes centralizadas** — todas las claves de Firestore, localStorage y Remote Config viven en `app.constants.ts`. Un cambio de nombre se hace en un solo lugar.
**Componentes de responsabilidad única** — `TaskItemComponent` solo renderiza, `Tasks` service solo gestiona estado, `LocalTasksDataSource` solo persiste. Cada pieza es testeable de forma aislada.
**TypeScript estricto** — sin `any` explícito, tipado de modelos con interfaces, `as const` para objetos de configuración. El compilador detecta errores de contrato antes de tiempo de ejecución.
**Estructura por features** — `tasks/` y `categories/` son módulos autocontenidos con sus componentes, servicios y pipes. Escalar o eliminar una feature no afecta el resto de la app.