Arquitectura de Cosmic Story v2: un análisis a fondo.

Para ingenieros, PMs, periodistas y exploradores de alianzas. El pipeline completo, cuatro colecciones de MongoDB, eventos EDA, el rigor del modelo en V, objetivos de rendimiento, seguridad y accesibilidad: todo en una sola página.

  • Soulwise-story es un nuevo módulo de NestJS junto al módulo cosmic-story existente. Cero importaciones directas entre módulos de funcionalidad.
  • Cuatro colecciones de MongoDB: soulwise_persons, soulwise_chapters, soulwise_journal_entries, soulwise_resonances. Cuerpos cifrados con AES-256, indexados para las consultas que sirve cada una.
  • Generación asíncrona mediante una cola de BullMQ con un tiempo de espera de 28 s. Los eventos se emiten a través de EventEmitter2 solo después del commit en la base de datos: sin elementos fantasma en la bandeja de entrada.
  • Especificación de Modelo en V: 119 requisitos, cero brechas. Objetivo de cobertura del backend: 85% de sentencias en los servicios; frontend 90% en los stores de Pinia.

El pipeline, de nuevo, con detalle de ingeniería

Cada paso tiene un servicio, un contrato y un evento.

  1. Disparador

    Una acción del usuario —«genera el capítulo de hoy para Hermana»— o un cron programado, como el resumen del domingo a las 9 a. m., o la actualización del clima cada 6 horas.

  2. Cola

    El trabajo llega a una cola de BullMQ llamada soulwise-chapter-generation, con un tiempo de espera máximo de 28 segundos. Los trabajos que se prolongan se cancelan y se le informan al usuario como «inténtalo de nuevo».

  3. Componer

    El ChapterGenerationService ensambla el prompt de cuatro factores —contexto de la persona, astrología, señal, ritmo— en una sola entrada. Ningún dato personal en bruto del usuario entra al prompt de forma literal; todo se depura primero.

  4. Generar

    Se invoca a un proveedor de IA mediante el token simbólico AI_GENERATION_ADAPTER, y el proveedor es intercambiable. Antes de continuar, se verifica la longitud, la forma y la seguridad de la respuesta.

  5. Posprocesar

    Suceden cuatro cosas: un clasificador de crisis detecta lenguaje de crisis; un extractor de chips de aspecto saca de uno a tres chips astrológicos; un filtro antiafirmaciones elimina las formulaciones prohibidas; y el cuerpo se cifra con AES-256 usando una clave gestionada por la plataforma.

  6. Persistir

    El artefacto se escribe en la colección de MongoDB correspondiente —capítulos, entradas del diario, resonancias— con índices userId y personId para una búsqueda rápida. Primero se borra de forma lógica; el borrado definitivo de la información personal se realiza a los 30 días.

  7. Notificar

    Un evento de EventEmitter2 —CHAPTER_COMPLETED, JOURNAL_CREATED— se dispara tras confirmarse el commit en la base de datos. El módulo de notificaciones lo recoge, crea un elemento en la bandeja de entrada y, opcionalmente, envía una notificación push (limitada a una al día y respetando las horas de silencio).

  8. Mostrar

    El frontend obtiene el artefacto mediante una llamada autenticada a la API. El Hub se vuelve a renderizar con el nuevo contenido. Si el usuario estaba sin conexión, la caché muestra la vista de ayer y el nuevo artefacto aparece al reconectarse.

Siete pasos desde el disparador hasta la entrega, cada uno nombrado según lo que realmente hace.

Las cuatro colecciones

Indexadas para las consultas que responde cada una.

soulwise_persons

Entradas del álbum. Índices en userId, status, deletedAt. Primero borrado lógico; borrado físico de los datos personales a los 30 días.

soulwise_chapters

Capítulos escritos por la IA, cuerpo cifrado. Índices en personId, userId, generatedAt. Las fichas de aspectos se almacenan en un array independiente para filtrar con rapidez.

soulwise_journal_entries

Reflexiones escritas por el usuario, cuerpo cifrado. Índices en userId, personId, createdAt. Cuerpo con índice de texto para la búsqueda. Marca por entrada «privado: no compartir con Luminara».

soulwise_resonances

Puntuaciones de cuatro dimensiones por vínculo. Índice único en personId. Se recalcula mediante una llamada al servicio tras escribir un capítulo o una entrada del diario.

Eventos EDA

Regla estricta: los eventos se disparan solo después del commit en la base de datos. Las dependencias entre módulos se gestionan mediante tokens de inyección Symbol, nunca con forwardRef. Sin imports directos de servicio a servicio entre módulos de funcionalidad.

  • SoulwiseEvents.CHAPTER_COMPLETED — SoulwiseEvents.CHAPTER_COMPLETED — se dispara después de cifrar y persistir un capítulo. Notifications-v2 escucha; crea el elemento en la bandeja de entrada; opcionalmente envía un push.
  • SoulwiseEvents.JOURNAL_CREATED — SoulwiseEvents.JOURNAL_CREATED — se dispara después de cifrar y persistir una entrada del diario. El servicio de resonancia escucha; activa el recálculo.
  • SoulwiseEvents.PERSON_BIRTH_UPDATED — SoulwiseEvents.PERSON_BIRTH_UPDATED — se dispara después de que cambian los datos de nacimiento de una persona. La caché de sinastría se invalida.
  • SoulwiseEvents.PUSH_REQUESTED — SoulwiseEvents.PUSH_REQUESTED — según el contrato de notifications-v2; respeta el presupuesto de push y las horas de silencio.

Rigor de especificación del Modelo en V

119 requisitos trazables, cero brechas. Cada requisito se vincula hacia adelante con un caso de prueba (UTP, ITP, STP, E2E) y hacia atrás con una historia de usuario. 20 historias de usuario. 15 requisitos funcionales. 12 categorías no funcionales. 8 puertas de aceptación globales.

Contrato de rendimiento

Generación de capítulos en 30 segundos o menos para el 95% de las solicitudes, medida frente a la distribución de duración de los trabajos de BullMQ. Latencia de la API p99 en GET de 500 ms o menos con 1,000 usuarios concurrentes, medida mediante una prueba de carga con k6. TTI del frontend de 3 segundos o menos en 4G simulado, medido con Lighthouse CI.

Contrato de seguridad

Cifrado AES-256 en reposo con claves gestionadas por la plataforma para los cuerpos de diario y capítulo. TLS 1.2+ en tránsito; redirección de HTTP→HTTPS. Tokens de acceso JWT con vida útil de 1 horas, tokens de actualización con vida útil de 30 días, con rotación al refrescar. Eliminación lógica con una ventana de 30 días antes de la eliminación definitiva de los datos personales.

Contrato de accesibilidad

prefers-reduced-motion se respeta de forma global: las animaciones de GSAP se convierten en fundidos solo de opacidad. Etiquetas de VoiceOver y TalkBack en cada elemento interactivo. Verificado manualmente en iOS y Android antes de cada lanzamiento.

¿Por qué un módulo soulwise-story aparte en lugar de ampliar cosmic-story?

Porque la especificación upstream reconstruye la función, y reconstruirla dentro de un módulo existente rompería la experiencia v1 o forzaría un fork-then-merge más adelante. Un módulo nuevo mantiene v1 intacto, deja que v2 demuestre su valía y migra de forma limpia cuando esté listo.

¿Por qué MongoDB y no Postgres?

El backend actual de My Zodiac AI está en MongoDB; cambiar implicaría una decisión de infraestructura ajena a esta función. El modelo de documentos también encaja bien con capítulos y entradas de diario: anidados, de longitud variable, cifrados como blob.

¿Por qué se eligió BullMQ como cola?

BullMQ corre sobre Redis, que ya está en el stack para sesión y límite de tasa. Sin infraestructura nueva. Los reintentos, los timeouts y la observabilidad integrados cubren las necesidades de generación de capítulos sin tuberías a medida.

¿Dónde está documentada realmente la especificación upstream?

En el repositorio interno. Los números y contratos de esta página parafrasean los artefactos del Modelo en V upstream. Las entradas del blog de ingeniería de cara al público en el clúster de blogs de My Zodiac AI (con la etiqueta 'cosmic-story-v2') profundizan en partes concretas de la construcción.

Prueba My Zodiac AI hoy mismo

Mientras Soulwise abre sus olas, nuestra app insignia de astrología ya está en tus manos.

El contenido astrológico es para la reflexión y el entretenimiento. Las funciones de Cosmic Story v2 que se describen aquí están en desarrollo; su disponibilidad puede cambiar sin previo aviso.