Arquitectura de Cosmic Story v2: una mirada a fondo.

Para ingenieros, PMs, periodistas y exploradores de alianzas. El pipeline completo, cuatro colecciones de MongoDB, eventos EDA, rigor del V-Model, 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 atiende cada uno.
  • Generación asíncrona mediante una cola de BullMQ con tiempo de espera de 28 s. Los eventos se emiten con EventEmitter2 solo después de confirmar en la base de datos: sin elementos fantasma en la bandeja de entrada.
  • Especificación en modelo V: 119 requisitos, cero brechas. Meta de cobertura del backend: 85% de instrucciones en los servicios; frontend 90% en los stores de Pinia.

El pipeline, otra vez, con detalle de ingeniería

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

  1. Disparador

    Una acción del usuario —"generar el capítulo de hoy para Hermana"— o una tarea programada (cron), 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 límite estricto de 28 segundos. Los trabajos que tardan demasiado se cancelan y se le informa al usuario como "intenta de nuevo".

  3. Componer

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

  4. Generar

    Se llama a un proveedor de IA mediante el token de símbolo AI_GENERATION_ADAPTER; el proveedor es intercambiable. La respuesta se verifica en longitud, forma y seguridad antes de continuar.

  5. Posprocesar

    Ocurren cuatro cosas: un clasificador de crisis revisa si hay lenguaje de crisis; un extractor de chips de aspecto obtiene de uno a tres chips de astrología; un filtro anticlaim elimina las formulaciones prohibidas; 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 de diario, resonancias— con índices userId y personId para una búsqueda rápida. Primero borrado lógico; borrado definitivo de la PII a los 30 días.

  7. Notificar

    Un evento de EventEmitter2 —CHAPTER_COMPLETED, JOURNAL_CREATED— se dispara después del 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 por día, 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 con el nombre de 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 definitivo de la PII a los 30 días.

soulwise_chapters

Capítulos escritos por IA, con el cuerpo cifrado. Índices en personId, userId, generatedAt. Los chips de aspectos se almacenan en un arreglo aparte para filtrar más rápido.

soulwise_journal_entries

Reflexiones escritas por el usuario, con el cuerpo cifrado. Índices en userId, personId, createdAt. Cuerpo con índice de texto para búsquedas. Marca por entrada de '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 de EDA

Regla estricta: los eventos se disparan solo después del commit en la base de datos. Las dependencias entre módulos se manejan mediante tokens de inyección Symbol, nunca con forwardRef. No se permiten importaciones directas de servicio a servicio entre módulos de funcionalidades.

  • SoulwiseEvents.CHAPTER_COMPLETED — SoulwiseEvents.CHAPTER_COMPLETED — se dispara después de que un capítulo se cifra y se persiste. Notifications-v2 está a la escucha; crea un elemento en la bandeja de entrada; opcionalmente envía un push.
  • SoulwiseEvents.JOURNAL_CREATED — SoulwiseEvents.JOURNAL_CREATED — se dispara después de que una entrada del diario se cifra y se persiste. El servicio de resonancia está a la 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. Se invalida la caché de sinastría.
  • 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 mapea hacia adelante a un caso de prueba (UTP, ITP, STP, E2E) y hacia atrás a 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 contra 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 con prueba de carga k6. TTI del frontend de 3 segundos o menos en 4G simulada, medida con Lighthouse CI.

Contrato de seguridad

Cifrado AES-256 en reposo con claves gestionadas por la plataforma para los cuerpos del diario y de los capítulos. 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, rotación al actualizar. Borrado lógico con ventana de 30 días antes del borrado definitivo de la PII.

Contrato de accesibilidad

prefers-reduced-motion se respeta globalmente: las animaciones de GSAP se convierten en transiciones solo de opacidad. Etiquetas para 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 extender 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 valor y migra de forma limpia cuando esté listo.

¿Por qué MongoDB y no Postgres?

El backend actual de My Zodiac AI corre sobre MongoDB; cambiarlo implicaría una decisión de infraestructura ajena a esta función. Además, el modelo de documentos 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 sesiones y límite de tasa. Sin infraestructura nueva. Los reintentos, tiempos de espera y observabilidad integrados cubren las necesidades de generación de capítulos sin plomería personalizada.

¿Dónde está realmente documentada 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 publicaciones del blog de ingeniería de cara al público en el clúster de blog de My Zodiac AI (etiquetadas como 'cosmic-story-v2') profundizan en partes específicas de la construcción.

Prueba My Zodiac AI hoy

Mientras Soulwise abre sus olas, nuestra app de astrología insignia 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; la disponibilidad puede cambiar sin previo aviso.