Nébula
Nébula

Portadilla

Nébula

Tu biblioteca personal inmersiva: importa tus EPUB y viaja.

App móvil de lectura · Flutter + Firebase2026

Diseño de producto, arquitectura y desarrollo completo (app Flutter, Cloud Functions, panel web y panel Android)

v1.0.0 completa y probada en dispositivo; pendiente de publicación en tiendas

Pasa página con ← → o baja

Portadilla · 01

Capítulo uno

Lectores sin biblioteca propia

Las apps de lectura serias son tiendas: viven de venderte su catálogo, atan tus libros a su cuenta y necesitan conexión para casi todo. Quien ya tiene sus EPUB —comprados sin DRM o de dominio público— se queda con lectores austeros que ni recuerdan el progreso decentemente, ni funcionan bien sin internet, ni ayudan a sostener el hábito. Y las que sí gamifican lo hacen empujando a competir con desconocidos, que es exactamente lo contrario de lo que busca alguien que lee para desconectar.

Catálogo ajeno

tus libros atados a una cuenta

Siempre en línea

sin red no hay casi nada

Competir

rankings con desconocidos

El problema · 02

Capítulo dos

El contenido lo pone el lector

Nébula invierte el modelo: el contenido lo pone el lector y la app pone todo lo demás. Un EPUB importado se convierte en texto plano que alimenta cuatro modos de consumo —lector paginado, lectura rápida RSVP, escucha por TTS y conversación con la IA Nova— y en la materia prima de la gamificación, porque de las palabras extraídas dependen el progreso, las estrellas y la rareza de las recompensas. Todo lo irremplazable se guarda en Hive dentro del teléfono; la red solo hace falta para lo que de verdad la necesita (la IA, la voz en la nube, la copia de seguridad y los avisos), y cada una de esas puertas degrada con elegancia cuando no hay internet.

Lector

8 temas · 10 tipografías

Lectura rápida

RSVP con letra pivote

Escucha

TTS con sesión de medios

Nova

IA sobre el libro abierto

La solución · 03

Capítulo tres

Seis decisiones que no se negocian

01

Offline-first de verdad

La biblioteca, el progreso, las citas, los resaltados, las estadísticas y toda la gamificación viven en 9 cajas de Hive dentro del teléfono. El modo de lectura rápida es offline duro: sus 8 ambientes visuales y sonoros van dentro del binario y no tiene un solo import de red.

02

Cuatro formas de leer el mismo libro

Lector paginado con 8 temas, 10 tipografías —Atkinson Hyperlegible incluida para dislexia— y anclaje de resaltados por coordenadas del documento; lectura rápida RSVP palabra a palabra con letra pivote; escucha por TTS con sesión de medios; y Nova, la IA que resume, explica y responde sobre el libro abierto.

03

Gamificación sin nadie más

76 cosméticos, 32 logros, misiones diarias y semanales, contratos de lectura con apuesta, pase de 50 niveles por temporada, un cielo de constelaciones donde cada libro terminado enciende una estrella y un diario. Ninguna función necesita otro usuario: compartir es exportar una imagen, nunca socializar dentro de la app.

04

La clave nunca viaja en el APK

Nova empezó llamando a Gemini desde el móvil con la clave embebida. Se movió entera a la Cloud Function novaGenerate, que guarda la clave, elige el modelo y aplica techos por usuario y globales. Firestore está cerrado a cal y canto: las reglas deniegan todo a los clientes y solo entra el Admin SDK.

05

39 idiomas con paridad verificada

1.929 claves por idioma, cargadas desde JSON sueltos para que añadir una lengua sea dejar caer un archivo. Una prueba recorre los catálogos reales y exige que cada clave derivada en código exista en todos los idiomas: es la que cazó cinco claves de Nova que se construían en tiempo de ejecución y se pintaban en crudo.

06

Copia de seguridad que no se rinde

Auto Backup de Android estaba roto sin saberlo: sin reglas declaradas respaldaba 109 MB, superaba el límite de 25 MB y dejaba de respaldar en silencio. Ahora respalda los 28 KB que importan, y un archivo .nebula exportable —ZIP versionado con manifiesto— cubre el cambio de plataforma y los EPUB que la nube no puede llevarse.

Seis certezas · 04

Lámina desplegable

Cinco pantallas, un mismo cielo

Recreadas en HTML y CSS con la paleta, las medidas y los ritmos reales de la app.

Nébula 12
TodosLeyendoPor leerTerminados
24

Tu semana lectora

Meta diaria · 24 de 30 min

12 días 8 libros

Favoritos

Ver todo

Mis libros

El jardín de las horas

M. Arriaga

Cartografía del insomnio

L. Berenguer

Los que miran arriba

T. Okonkwo

Nada que devolver

S. Vidal

Importar libro

Lo primero que se ve: la nebulosa propia, con la semana lectora arriba.

La interfaz · 05

Demostración

Quita la red y no se cae nada

Todo lo irremplazable vive en 9 cajas de Hive dentro del teléfono. La conexión solo hace falta para la IA, la voz en la nube, la copia de seguridad y los avisos: cuatro puertas que degradan con elegancia.

Lector paginado con capítulos, marcadores, búsqueda con salto a página, justificado, márgenes, velo de atenuado propio y menú de selección pegado al texto

Resaltados en 5 colores anclados a coordenadas del documento (párrafo + desplazamiento), inmunes al recálculo de paginación al cambiar letra o márgenes

Lectura rápida RSVP a pantalla completa con letra pivote, fondo Ken Burns temático, partículas y audio ambiental en bucle con fundido entre capítulos

Biblioteca con búsqueda, orden, filtros por estado de lectura, favoritos y estanterías personalizadas con 24 temas ilustrados por Canvas

Bóveda secreta con PIN: los libros ocultos no aparecen en ninguna superficie de la app fuera de la bóveda, ni siquiera en citas, resúmenes o contratos

Pase de temporada de 50 niveles por bimestre con eventos temáticos por calendario

Constelaciones: cada libro terminado se convierte en una estrella con posición estable por hash FNV-1a, agrupada en 8 constelaciones por género

Recordatorios locales de 5 tipos, sin FCM y sin internet, apagados de fábrica y con alarmas inexactas a propósito

Widget de pantalla de inicio en Android que se repinta al volver a primer plano y compara el día guardado con el del sistema

Sin internet · 06

Las cifras

Doce estrellas, un solo cielo

158

archivos Dart en la app

~99.200

líneas de Dart

31

rutas de pantalla registradas

26

Cloud Functions en Node 22

39

idiomas soportados

1.929

claves de traducción por idioma

618

pruebas automatizadas

11

colecciones de Firestore

76

cosméticos en la tienda

32

logros

24

temas de estantería dibujados con Canvas

3

superficies: app, panel web y panel Android

Arrastra el cielo hacia los lados →

Constelación de cifras · 07

Bajo el capó

Tres superficies y una puerta cerrada

App Flutter

  • 158 archivos Dart
  • 9 cajas de Hive
  • 31 rutas

Cloud Functions

  • 26 funciones · Node 22
  • Nova, voz, pagos, correos
  • Admin SDK

Paneles

  • Web en React 19
  • Android en Flutter
  • Sin privilegios propios

Firestore · 11 colecciones

allow read, write: if false; — el único camino son las callables

Tres superficies sobre un único proyecto Firebase propio (nebula-e30fc). La app Flutter organiza sus 158 archivos Dart en core (tema, rutas, i18n, analítica, widgets), data (modelos Hive con adaptadores escritos a mano), features (una carpeta por módulo, 31 rutas nombradas registradas en main.dart) y services (unos 45 servicios de dominio inyectados con GetX). La persistencia es local por diseño: 9 cajas de Hive guardan libros, sesiones, citas, estanterías, resaltados, marcadores, contratos, diario y una caja meta cuyas claves llevan prefijo obligatorio por módulo (gm_, ct_, sp_, ev_, nv_, cl_, dy_, rn_). El servidor son 26 Cloud Functions en Node 22 repartidas en cuatro módulos —índice (Nova, voz en la nube, pagos manuales y membresías), panel, notificaciones push y correos— sobre 11 colecciones de Firestore. La decisión estructural del backend es que Firestore está cerrado a los clientes: las reglas deniegan todo y el único camino a los datos son las callables, que autorizan con Admin SDK; el panel web y el panel Android son, literalmente, pantallas sin privilegios propios. Nova y la voz en la nube pasan siempre por el servidor para que ninguna clave viaje en el binario, con cuota local en el móvil como pista de interfaz y el techo real aplicado en la función.

Tres superficies · 08

Aparato crítico

Seis notas al pie del proyecto

1

La clave de Gemini viajaba embebida en el APK. Un APK publicado lo descarga cualquiera, y esa clave estaba atada a una cuenta de facturación real: quien la extrajera podía gastar sin límite con cargo al dueño, y ninguna cuota en el móvil lo impide porque el atacante no pasa por el móvil.

Cómo se resolvió

Nova se partió en dos: el servicio del móvil solo compone la petición y la Cloud Function novaGenerate guarda la clave, elige el modelo y aplica un techo por usuario y otro global diario. La API pública del servicio (chat, resumen, personajes, cuestionario, explicar) se mantuvo idéntica, así que ninguna pantalla se enteró del cambio.

2

Nova dejó de responder de golpe sin haber tocado nada: el modelo gemini-2.5-flash empezó a devolver 404 por ser un proyecto nuevo, y el campo thinkingConfig que se usaba para vaciar el razonamiento pasó a devolver 400. El modelo seguía apareciendo listado en la API pese a rechazar las peticiones.

Cómo se resolvió

Se dejó de fijar un modelo por versión. Ahora hay una cascada de modelos encabezada por un alias que Google mantiene al día, y cada 404 o 400 lanza el reintento con el siguiente, probando cada modelo con y sin ajuste de razonamiento; el que funciona se cachea en memoria. La regla quedó escrita: nunca fijar una versión concreta de modelo en una app publicada.

3

Resaltar la palabra "que" teñía todas sus apariciones del libro. El primer intento —guardar los 40 caracteres previos como contexto— solo desambiguaba dentro de un párrafo, y como el pintado se aplica bloque a bloque, seguía marcando una aparición en cada párrafo que contuviera la palabra.

Cómo se resolvió

Identificar un resaltado por su texto es ambiguo por definición. Se ancló a coordenadas del documento: índice de párrafo dentro del capítulo más desplazamiento en el párrafo, que no cambian nunca, mientras que la paginación sí se recalcula al tocar letra o márgenes. El controlador de paginación pasó a exponer bloques con esas coordenadas y los párrafos se normalizan siempre, no solo al partirlos.

4

Android Auto Backup venía activado y estaba roto en silencio: sin reglas declaradas respaldaba el directorio entero, 109 MB de los que unos 106 MB eran assets que ya viajan dentro del APK, se pasaba del límite duro de 25 MB y dejaba de respaldar absolutamente todo sin avisar.

Cómo se resolvió

Se declararon reglas para las dos épocas de Android incluyendo solo lo irremplazable —28 KB de cajas Hive, portadas y preferencias— y excluyendo assets, EPUB y archivos de bloqueo. Verificado en dispositivo: la copia pasó de fallar a completar. Como Auto Backup no puede llevarse los EPUB ni cruzar de plataforma, se añadió además un archivo .nebula exportable y la re-vinculación de libros restaurados sin archivo conservando su identificador.

5

La capa de gamificación abría agujeros de economía difíciles de ver leyendo el código: firmar y cancelar un contrato inflaba el total histórico de estrellas y el rango, varios contratos idénticos resueltos por la misma sesión funcionaban como impresora, un doble toque en la tienda cobraba dos veces y el modo enfoque seguía pagando con el móvil bloqueado porque medía reloj de pared.

Cómo se resolvió

Revisión adversarial por dimensiones —economía, persistencia, ciclo de vida, integración, interfaz e idiomas— lanzada en tandas pequeñas. De ahí salieron una devolución que repone saldo sin tocar el histórico, el rechazo de contratos equivalentes con tope de activos, un cerrojo de compra y un cronómetro que solo corre en primer plano. Cada agujero quedó fijado por una prueba propia dentro de las 618 del repositorio.

6

Un panel de administración protegido solo por el correo del dueño no cerraba nada: la clave web del proyecto viaja dentro del APK de los lectores por diseño de Firebase, así que cualquiera podía registrar una cuenta con ese correo mientras no existiera y pedir la verificación, que llega al buzón legítimo del dueño.

Cómo se resolvió

La autorización exige tres condiciones a la vez en el servidor —correo del dueño, correo verificado y UID coincidente con el fijado en configuración— y falla cerrado si no hay administrador fijado. El UID es el que de verdad cierra la puerta. Ninguna contraseña vive en el binario, y hay una prueba en el repositorio que falla si alguna vez aparece un secreto.

Notas al pie · 09

Índice

Veintiuna entradas, todas dentro

01

Importación de EPUB desde el explorador de archivos o compartiendo desde otra app, con re-enlace de libros restaurados sin archivo que conserva progreso, citas y reseña

02

Lector paginado con capítulos, marcadores, búsqueda con salto a página, justificado, márgenes, velo de atenuado propio y menú de selección pegado al texto

03

Resaltados en 5 colores anclados a coordenadas del documento (párrafo + desplazamiento), inmunes al recálculo de paginación al cambiar letra o márgenes

04

Lectura rápida RSVP a pantalla completa con letra pivote, fondo Ken Burns temático, partículas y audio ambiental en bucle con fundido entre capítulos

05

Escucha por TTS del dispositivo con resaltado del párrafo actual, control de velocidad, temporizador de sueño y controles en la pantalla de bloqueo; voz en la nube opcional por minutos

06

Nova, la IA lectora: chat sobre el libro, resumen, fichas de personajes, cuestionario y explicación de un fragmento seleccionado

07

Biblioteca con búsqueda, orden, filtros por estado de lectura, favoritos y estanterías personalizadas con 24 temas ilustrados por Canvas

08

Bóveda secreta con PIN: los libros ocultos no aparecen en ninguna superficie de la app fuera de la bóveda, ni siquiera en citas, resúmenes o contratos

09

Economía de estrellas con multiplicador de racha, tope diario medido en minutos y una única puerta de concesión y gasto para evitar el farmeo

10

Misiones diarias y semanales derivadas de sesiones reales, ruleta ponderada y cofres

11

Contratos de lectura con apuesta de estrellas, escudo de racha, y modo enfoque cuyo cronómetro solo corre con la app en primer plano

12

Pase de temporada de 50 niveles por bimestre con eventos temáticos por calendario

13

Constelaciones: cada libro terminado se convierte en una estrella con posición estable por hash FNV-1a, agrupada en 8 constelaciones por género

14

Nova como compañera offline de 20 niveles con observatorio, auras, nido y guardarropa por capas dibujado con Canvas

15

Álbum de cartas por libro con rareza, jardín de 7 fases, insignias secretas, diario de lectura y resúmenes mensual y anual

16

Tarjetas compartibles de 1080×1920 para citas, logros, progreso, pulso del libro y resumen del año

17

Recordatorios locales de 5 tipos, sin FCM y sin internet, apagados de fábrica y con alarmas inexactas a propósito

18

Widget de pantalla de inicio en Android que se repinta al volver a primer plano y compara el día guardado con el del sistema

19

Copia de seguridad en la nube por lector, exportación manual a archivo .nebula y reglas de Auto Backup y exclusión de iCloud afinadas

20

Membresía con doble vía: suscripción de tienda y pago manual revisable desde el panel, con detección de doble cobro

21

Panel web de administración de seis pantallas y panel Android gemelo, ambos hablando solo con las Cloud Functions

Índice de funciones · 10

Bibliografía

Con qué está escrito

App móvil

FlutterDart 3.7GetXflutter_screenutilHiveshared_preferencespath_provider

Lectura y contenido

epub_prohtmlhtml_unescapefile_pickerarchiveflutter_ttsjust_audioaudio_serviceaudio_sessionwakelock_plus

Interfaz

Material 3google_fonts (Sora, Space Mono)flutter_animatelottiepercent_indicatorfl_chartcached_network_imagescreenshotshare_plus

Firebase y backend

firebase_corefirebase_authfirebase_analyticsfirebase_crashlyticsfirebase_messagingfirebase_storagecloud_functionsCloud Functions Node 22firebase-admingoogle-auth-libraryFirestore

Identidad y monetización

google_sign_insign_in_with_applegoogle_mobile_adsin_app_purchasein_app_purchase_androidcrypto

Sistema y utilidades

flutter_local_notificationstimezoneflutter_timezonehome_widgetconnectivity_plusurl_launcherpackage_info_plusintluuid

Panel web (nebula-web)

React 19TypeScriptViteTailwind CSSTanStack React QueryReact RouterRechartsthree.jslucide-reactdate-fnsoxlintFirebase Hosting

Panel Android (nebula-admin)

FlutterDartCloud Functions callable
Bibliografía técnica · 11

Láminas

La identidad del proyecto

Onboarding, imagen social y cabecera de los correos que envían las Cloud Functions. Arrastra.

Primera lámina del onboarding: una biblioteca que se deshace en nebulosa. Ilustración generada para el proyecto.
Primera lámina del onboarding: una biblioteca que se deshace en nebulosa. Ilustración generada para el proyecto.
Segunda lámina del onboarding: un libro emitiendo ondas con una estrella fugaz cruzando; representa los modos de lectura rápida y escucha.
Segunda lámina del onboarding: un libro emitiendo ondas con una estrella fugaz cruzando; representa los modos de lectura rápida y escucha.
Tercera lámina del onboarding: una llama de racha junto a libros y el búho; representa el hábito y la gamificación.
Tercera lámina del onboarding: una llama de racha junto a libros y el búho; representa el hábito y la gamificación.
Imagen social Open Graph de la web de Nébula: la identidad cósmica en formato apaisado.
Imagen social Open Graph de la web de Nébula: la identidad cósmica en formato apaisado.
Cabecera gráfica de los correos transaccionales que envían las Cloud Functions (aprobación de pago, membresía, aviso de administrador).
Cabecera gráfica de los correos transaccionales que envían las Cloud Functions (aprobación de pago, membresía, aviso de administrador).
Icono maestro de la aplicación: un libro que se abre en nebulosa, origen de los iconos de lanzador de Android e iOS.iconIcono de lanzador de Android generado a máxima densidad.iconIcono de la web para pantalla de inicio en iOS.iconFavicon vectorial de la web y el panel, en la paleta cósmica.favicon svg
Láminas · 12

Colofón

Lo que es Nébula

Nébula es un lector de ebooks offline-first para Android e iOS que no trae catálogo: el lector importa sus propios EPUB y la app los convierte en una biblioteca viva, con progreso, citas, resaltados y estadísticas que viven en el teléfono.

Sobre ese lector se monta una capa de hábito completamente individual —estrellas, misiones, contratos de lectura, pase de temporada, constelaciones, cartas y diario— construida bajo una regla dura de producto: nada que requiera otros usuarios, chat ni comparación social.

El ecosistema son tres superficies sobre un mismo proyecto Firebase: la app Flutter (158 archivos Dart, ~99.000 líneas), 26 Cloud Functions en Node 22 y dos paneles de administración, uno web en React y otro Android en Flutter.

Está traducida a 39 idiomas con 1.929 claves por idioma y sostenida por 618 pruebas automatizadas repartidas en 68 archivos, varias de ellas escritas expresamente para fijar agujeros de economía encontrados en revisiones adversariales.

Paleta

#6C4DF4

primary

#4D9FF4

secondary

#22D3EE

accent

#0B0E1D

bg

#141A33

surface

#F2F4FF

text

Cósmico nocturno y editorial: azul de medianoche profundo, violeta de nebulosa y un cian eléctrico que solo se usa para lo que brilla de verdad. Tipografía Sora para leer y Space Mono para las cifras. Es oscuro siempre, a propósito, porque la app se usa de noche y con la cara pegada a la pantalla.

Año

2026

Categoría

App móvil de lectura · Flutter + Firebase

Estado

v1.0.0 completa y probada en dispositivo; pendiente de publicación en tiendas

Un lector que no vende libros: los recibe, los cuida y los convierte en un cielo propio.

resaltados por coordenadas 39 idiomas gamificación sin nadie más
Colofón · 13

Nébula

¿Quieres algo así para tu producto?

Una app offline-first con lector propio, IA servida desde el backend y una capa de hábito que no necesita a nadie más. Si tienes algo así en la cabeza —Flutter, Firebase, producto entero— es exactamente el terreno que conozco.