📋 Versión y Log

Historial de cambios de la aplicación

v3.16.8
€” 2026-09-23

MAIA — Astro Chart Application

Aplicación de cartas natales

CHANGELOG



v3.16.8 — 2026-09-23



Añadido


  • Página «Personalitzar programa» (/personalizar, antes «Orbes» en el menú): pestanyes verticals Orbes (contingut actual extret a partes/_orbes_form.php; /orbes segueix funcionant) + Colors (pickers per aspecte amb símbol, roda i taules, presets i desat). Traduït a ca/es/en.

  • Colores por usuario (UserColorManager, tabla user_colors, migración incluida): se aplican a las tablas (vars CSS :root por usuario) y a la rueda SVG (WheelRenderer usa wheelColor() con contexto de RequireLogin/ajax/main). Endpoint ajax/save-colors.php.

  • Vista de carta: nombre centrado y en grande (.chart-person-name); eliminado el subtítulo «Nacimiento: …» del header.

  • Títulos que replican la pestaña activa (estilo .filter-header, variante --plain) entre pestañas y contenido en Carta y Resumen.


Cambiado


  • Pestaña activa: detección por onclick en vez de por texto (antes solo funcionaba en español); 1.425rem base y 2rem en tabs globales, en negrita.

  • Botón «Calcular Progressions»: ocupa su celda del grid sin desbordar.

  • Etiqueta de orbe: «Conjunció de planeta amb angles i nodes» (ca/es/en), situada entre conjunció i oposició. La clave BD (angle_conjunction) no cambia: se conservan valores guardados.

  • Tablas de aspectos: unificadas con los colores de la rueda (--prog-asp-*; arrastra a direccions i lunacions). transitos.css mantiene su paleta propia.

  • robots.txt nuevo (bloquea testing/logs/admin).


Corregido


  • Reset de orbes (por tipo y total): llamada incorrecta a Database::delete() (espera array, recibía string) que lanzaba excepción; ahora query() directo y verificado (vuelve al defecto). Mismo patrón detectado sin corregir en admin/coupons.php:65 y admin/treasury.php:30.


v3.16.7 — 2026-09-23



Añadido


  • Informe · Condiciones especiales: nueva condición conjunción a un eje (ASC, DSC, MC, IC) y conjunción a los nodos (Norte, Sur), con el orbe y formato «Conjunción con … (orbe …°)».

  • Tabla de orbes: nuevo campo «Conjunció de planeta amb angle» (solo Carta Natal, valor por defecto 8°) que define el orbe de la conjunción planeta-eje y planeta-nodos del informe. Etiqueta traducida a ca/es/en.


Cambiado


  • Informe · fichas de planeta: eliminados los paréntesis rojos junto a grado/signo (la info queda solo en «Condiciones especiales»).

  • Informe · tamaños: fila Casa: N, título Condiciones especiales: y sus ítems a 1.4rem como .informe-planet-position (1rem en móvil).


v3.16.6 — 2026-09-23



Añadido


  • «Probar como grupo» (simulador de perfiles): Rei do Mambo puede simular cualquier grupo desde el dashboard (selector 🎭 con ajax/change_group.php + ruta registrada). Banner visible «Estás probando el perfil» con botón «Volver a mi perfil». Límites de cartas, banners de cuota y cabecera respetan el grupo efectivo (AuthManager::getEffectiveGroup(), inRealGroup()).

  • Datos de la persona · Residencia por país: el bloque de residencia se muestra cuando el país de residencia difiere del de nacimiento (extraído del display_name de GeoNames). Nuevas filas País y Hora local (residencia) (instante natal expresado en la zona de residencia).

  • Títulos que replican la pestaña activa (estilo .filter-header, variante --plain sin engranaje) entre pestañas y contenido en Carta (dibujo) y Resumen; switchRelocGlobal los sincroniza en todos los idiomas.

  • i18n: workflow obligatorio documentado en AGENTS.md (texto → __() → .po ca/es/en → msgfmt → reload PHP-FPM → verificar).


Cambiado


  • Selector de idioma: solo ca/es/en visibles, salvo grupo real Rei do Mambo (partes/header.php; respeta el override para simular fielmente).

  • Deploy: deploy:restart_services condicional — omite el restart de PHP-FPM/Nginx si la release es idéntica a la anterior (diff excluyendo shared); garantiza catálogo gettext fresco cuando cambian los .mo.

  • Informe: renderFaseLuna() reutilizada también en la pestaña de residencia; bloque de Quirón solo con permiso de síntesis.

  • Pestaña activa: texto más grande + negrita (1.425rem base, 2rem en tabs globales de informe); detección por onclick en vez de por texto (antes solo funcionaba en español).

  • Botón «Calcular Progressions»: ocupa su celda del grid sin desbordar (#prog-btn-calcular).


Corregido


  • Fase lunar en inglés: obtenerFasesLluna() devolvía el JSON en castellano sin pasar por __(); ahora se traduce al consumir (mismo patrón que Quirón). «Casa X» del listado detallado de Direcciones (2 puntos), «orbe de» de Lunaciones (2 puntos) y textos de TooltipData (helper recursivo traducir() en los 4 métodos) ahora usan __().

  • i18n ca/es/en: +150 entradas de TooltipData traducidas (+12 strings técnicos lado/IDs dejados idénticos a propósito; +12 nombres de elementos/modalidades/polaridades en ca). en_US reparado (línea basura + 60 comillas sin escapar). Cadenas del simulador de perfiles traducidas a de/fr/it/pt; .pot regenerado.


v3.16.5 — 2026-09-22



Corregido


  • Informe · fichas de planeta: restaurada la sección «Planetas» con una ficha por planeta (nombre, posición, Casa, Rige, Condiciones especiales, Aspectos). Se refactorizó en renderSeccionPlanetas() y ahora aparece tanto en la carta natal como en la residencia (antes solo existía en la pestaña natal, y al mostrar Residencia por defecto parecía que habían desaparecido).

  • Orden de los planetas en la tabla de posiciones y en las fichas: Sol, Luna, Mercurio, Venus, Marte, Júpiter, Saturno, Urano, Neptuno, Plutón, Quirón.


Cambiado


  • Permiso «Ayudas» (view_help_guides): ahora controla también los subtítulos-pregunta del Balance Astral («¿Cuál es la naturaleza predominante…?») y de Hemisferios y cuadrantes («¿Dónde se manifiesta esa energía…?»), además de las guías de lectura. Sin el permiso, no aparecen.

  • Planeta focal: la condición especial indica el patrón y los planetas relacionados (p. ej. «Planeta focal de T-Quadrada (amb Júpiter, Saturn») y se repite si el planeta es focal de más de un patrón.

  • Botones Imprimir y Compartir (vista de carta): visibles solo para el grupo Rei do Mambo.


v3.16.4 — 2026-09-22



Añadido


  • Permiso «Ayudas» (view_help_guides): nuevo permiso en *Permisos avanzados*. Controla la visibilidad de la guía de lectura (tablas de coherencia) del Balance Astral y de Hemisferios y cuadrantes en el informe. Migración add_help_guides_permission.sql (asignado a Administrators, Rei do Mambo, Usuario registrado y Aula).

  • Informe · Condiciones especiales: en la ficha de cada planeta, tras «Rige:» y antes de «Aspectos:», aparece un apartado «Condiciones especiales» solo si hay alguna: retrógrado/estacionario, función inferior (elemento único, modalidad única, grado 29°), regente de la carta y planeta focal de un patrón de aspectos.

  • Datos de la persona · Residencia: se añade la Hora UTC del bloque de residencia (mismo instante que el nacimiento expresado en UTC).


Cambiado


  • Pestaña de residencia por defecto: cuando la carta tiene residencia distinta del lugar de nacimiento, la vista predeterminada es Residencia (carta, informe y resumen); «Nacimiento» queda como pestaña secundaria.


v3.16.3 — 2026-09-22



Cambiado


  • Informe · Planetas: eliminada la sección «Planetas más influyentes» (con puntuación numérica), tanto en la carta natal como en la residencia. La tabla de posiciones pasa a incluir una columna cualitativa «Qualitats» con etiquetas: Angular, Retrógrado/Estacionari y Focal (punto focal de un patrón de aspectos). Sin puntuación.

  • Export IA: eliminada la sección «Planetas más influyentes (pts)» del texto exportado.

  • Progresiones: eliminada la sección «Evolució del panorama (Hemisferis, Elements...)» del resumen.

  • Código muerto eliminado: CalculadorInfluenciaPlanetas::calcular() ya no se invoca y sus llamadas en charts/view.php y el método ProgressionsCalculator::generarEvolucionBalance() han sido retirados. La clase CalculadorInfluenciaPlanetas se conserva (sin uso).


v3.16.2 — 2026-09-22



Cambiado


  • i18n (en_US, fr_FR, de_DE, it_IT, pt_PT): completadas las traducciones de los 5 idiomas restantes (antes caían al catalán/castellano).

- messages.pot regenerado con xgettext: faltaban ~200 msgids que no estaban en ningún catálogo.
- msgmerge aplicado a los 7 idiomas.
- Entradas fuzzy eliminadas (~1.400 que msgfmt ignoraba y quedaban sin traducir).
- Traducidas todas las cadenas pendientes, incluidas las multilínea y las formas plurales (%d carta de %d disponible).
- Corregida una contaminación sistemática en en_US (29 cadenas traducidas erróneamente con «lunations»).
- Traducción asistida por el modelo local (qwen3.6:27b); pendiente de revisión humana en detalles finos.

v3.16.1 — 2026-09-22



Añadido


  • Informe · tabla de posiciones: nueva tabla compacta (Planeta · Posición · Casa · Movimiento) al principio de la sección «Planetas» del informe, con grado·signo, casa y movimiento. Solo se muestra el movimiento si no es directo (Retrógrado/Estacionario). El texto de «Resumen carta» omite «directo» y ya contempla los estados estacionarios (SR/SD/S).


Cambiado


  • Impresión: el PDF de la carta imprime únicamente la rueda, el panel de planetas y la cuadrícula de aspectos (oculta el resto de la interfaz) y escala la cuadrícula para que quepa en un A4 horizontal.

  • Precios en euros: solo se muestra el precio en € (se elimina el $ y la aproximación USD→EUR). En BD, subscription_prices pasa a 8 €/mes y 60 €/año; STRIPE_CURRENCY=EUR.

  • «més cara» → «més alta» en el aviso de cuota mensual (dashboard.php), con las traducciones actualizadas.


Migraciones


  • update_free_group_max_charts.sql — límite de cartas de los grupos gratuitos a 5.

  • update_subscription_prices_eur.sql — precios a 800 / 6000 céntimos (8 € / 60 €).


v3.16.0 — 2026-09-22



Corregido


  • i18n (catalán/castellano): se han traducido al catalán las cadenas cuyo msgid estaba en castellano y que se mostraban en castellano aunque el idioma fuera catalán (~330 cadenas en admin/*, auth/*, dashboard.php, charts/*, includes/*, partes/*). El catálogo ca_ES pasa a mostrar catalán en todas esas pantallas.

  • Strings hardcoded envueltos con __(): admin/textos.php (Tabla de Coherencia, Balance, Hemisferios, Nombre, Pregunta) y admin/email-logs.php (De:, Para:, Fecha:, Asunto:).

  • Nuevos msgids añadidos a los 7 idiomas: Hemisferios, De:, Para:, Asunto:, Balance, Tabla de Coherencia. Todos los .mo recompilados con msgfmt.


Cambiado


  • Colores de aspectos (carta natal, tránsitos y progresiones):

- Oposición y cuadratura: rojo.
- Trígono y sextil: azul (el sextil pasa de verde a azul).
- Semisextil, semicuadratura, sesquicuadratura y quincuncio: verde.
- Archivos: includes/Symbols.php, css/transitos.css, css/progressions.css.

v3.15.7 — 2026-09-19



Cambiado


  • Progressions · Texte: la subpestaña Texte ya no se muestra si el usuario no tiene el permiso access_ia_export («Exportar para IA»). Al no tenerlo, tampoco se genera el texto plano (renderTextoPlano). renderPestanyes() recibe ahora bool $canViewTextTab y construye el botón y el panel de texto solo si se permite.


v3.15.6 — 2026-09-19



Añadido


  • RS · Texto: la subpestaña Texto incluye ahora todo lo del Informe. Se añaden Sol de RS y Patrons d'aspectes de la RS (amb la casa de cada planeta a cada ubicació, N/R/E). La resta (balanç comparatiu, cases carregades, planetes angulars, contactes nodes, angles natals a cases RS, ASC de RS, superposició, planetes RS per casa, contactes RS-Natal i regents) ja s'hi generava. renderTextoPlano() rep ara $results (opcional) i per això pot mostrar les cases de les tres ubicacions.


v3.15.5 — 2026-09-19



Cambiado


  • RS · Patrons d'aspectes: la targeta ahora se muestra dentro de la caja «Dades de posicionament» y a todo lo ancho (fuera de la rejilla de 2 columnas), en lugar de como tarjeta independiente del Informe.


v3.15.4 — 2026-09-19



Añadido


  • RS · Patrons d'aspectes: dins de la subpestanya Informe de cada ubicació es mostren els patrons detectats a la carta RS (T-Quadrada, Gran Trígon, Estel·li...), amb els planetes i la casa que ocupen a cada ubicació, prefixada amb N: natal, R: residència, E: elegida. Els planetes de la RS són idèntics a les tres ubicacions; només canvien les cases (ASC/MC). Els nodes i angles no entren mai als patrons (el detector filtra a PLANETAS_Y_QUIRON_CARTA).


v3.15.3 — 2026-09-19



Corregido


  • RS · Contactes Nodes: ahora se consideran los dos nodos (Norte y Sur) y la distancia se calcula comparando la distancia angular real (distAngular) con el ángulo del aspecto. Antes solo se probaba nodo + ángulo, por lo que se perdían todos los aspectos del lado contrario (p. ej. la sesquicuadratura al Nodo Sur). Cada nodo recibe su aspecto correcto: un planeta a 45° del Nodo Norte está a 135° del Nodo Sur.

- Verificado en la carta 3 (RS 2026): Lluna Quincunci NN 0,14° / Semisextil NS 0,14°; Saturn Semiquadratura NN 0,83° / Sesquiquadratura NS 0,83°.

v3.15.2 — 2026-09-19



Corregido


  • RS · Contactes Nodes (≤1°): solo detectaba conjunción y oposición. Ahora considera todos los aspectos mayores y menores (conjunción, oposición, trígono, cuadratura, sextil, semisextil, semiquadratura, sesquicuadratura, quincuncio) a ≤1° del Nodo Norte, ordenados por orbe. En la carta 3 aparecen contactos antes invisibles (Lluna Quincunci 0.14°, Saturn Semiquadratura 0.83°).


Documentación


  • documentation/maia_ai_local_module.md reescrito: describía el proyecto Python externo obsoleto; ahora documenta el pipeline PHP real (4 pasadas, porta de cobertura, RAG, traces, xat, aturada, QA).

  • documentation/revolucio_solar_module.md ampliado: constructor con $casasResidencia, DES/FC en angles natals, posició de l'ASC de RS (carta natal i residència), criteri de cases carregades, contactes amb nodes per qualsevol aspecte.

  • .env.example: MAIA_SYNTHESIS_MODEL, MAIA_DIGEST_MODEL, MAIA_OLLAMA_MODEL (legacy).


v3.15.1 — 2026-09-19



Corregido


  • RS · Cases carregades: el criteri pasa de "2+ planetes" a 3+ planetes, o bé 2+ planetes amb almenys un node. Quirón cuenta como planeta. Se muestran también los nodos de la casa. Etiquetas actualizadas en los 7 idiomas.

  • RS · text pla de Cases carregades: mostrava la casa buida (Casa 2: ) porque leía los planetas con array_column(...,'planeta') sobre una lista de strings. Ahora lista los nombres correctamente.


v3.15.0 — 2026-09-19



Release a producció. Consolida v3.14.0–v3.14.24 i tanca codi pendent
de MAIA AI.

Añadido


  • MAIA AI · RAG i xat: includes/MaiaRagStore.php, scripts/maia_rag_index.php (índex local d'embeddings), includes/MaiaChatSession.php (sessions de conversa en disc amb TTL), corpus astrològic local (gitignored).

  • MAIA AI · robustesa del pipeline: MaiaRagStore::trocear() parteix per frases els paràgrafs gegants; tolerància a fragments OCR invàlids; .env.example amb MAIA_OLLAMA_URL/MODEL/MAIA_RAG_MODEL.

  • RS: secció CÚSPIDES DE LES CASES a l'export (ajax/ia_export.php); "Angles natals a cases RS" amb les 4 xifres (ASC/MC derivats de DES/FC); ASC de RS amb posició a la carta natal i de residència, àngle (ASC/FC/DES/MC) i distància a les dues cúspides; etiquetes Regent/Natal/Residencia en negreta.

  • MAIA AI · QA/cobertura: MaiaPipeline::verificarCobertura() amb reintent, lineaNodal()/miembrosEnfasis()/cuspidesAngulares() deterministes; model de cada passada a les traces.


Corregido


  • Síntesis 30B vacía (sense thinking); digest per defecte a devstral-small-2:24b; falsos negatius del QA nodal i de dates amb guions.


v3.14.24 — 2026-09-19



Corregido


  • RS · ASC de RS: las etiquetas "Regent:", "Natal:" y "Residencia:" en negrita (<strong>).


v3.14.23 — 2026-09-19



Corregido


  • RS · ASC de RS: distancia a las dos cúspides de su casa: en vez de un único orbe ambiguo, ahora indica el tramo completo, p. ej. "Casa 11, a 8' de la cúspide de la casa 11 i a 26° 10' de la cúspide de la casa 12" (entrada y salida). La casa se nombra con el ángulo (ASC/FC/DES/MC) cuando el punto está junto a la cúspide de una casa angular. Nuevo posicioNatal() devuelve orbe_ini/orbe_fin, casa_siguiente y textos; fmtOrbe() compartido. Envoltorio i18n único traducido a los 7 idiomas (el msgid anterior de la cúspide queda retirado).


v3.14.22 — 2026-09-19



Corregido


  • RS · ASC de RS: nombrar la cúspide de referencia: "Casa 11 · 8' de la cúspide" era ambiguo (¿a qué cúspide?). Ahora indica la cúspide vecina cuando no es la propia: "Casa 10 · 6' de la cúspide (Casa 11)". La etiqueta angular (ASC/FC/DES/MC) solo se usa cuando el punto está junto a la cúspide de su propia casa; si está al final de una casa angular, se nombra la casa y la cúspide vecina. (Nota: el "Casa 11 · 8'" real de la carta 3 es correcto —ASC RS 26°50′ está 8' DESPUÉS de la cúspide de casa 11 a 26°42′; el 26°36′ era un ejemplo hipotético.)


v3.14.21 — 2026-09-19



Añadido


  • RS · ASC de RS: posición en la carta natal (y de residencia): la tarjeta "ASC de RS" ahora indica en qué casa de la carta natal cae el ASC de la RS, con el orbe a la cúspide más cercana ("MC · 7' de la cúspide"). En casas angulares muestra el ángulo (casa 1→ASC, 4→FC, 7→DES, 10→MC) en lugar del número. Si el usuario tiene carta de residencia y permiso relocation_access, se muestra también respecto a sus casas relocalizadas. Nuevo RevolucioSolarCalculator::posicioNatal(), etiquetaAngular(), textPosicio(); constructor acepta las casas de residencia (pasadas desde ajax/revolucio_solar.php). Nuevo msgid de la cúspide en 7 idiomas (.po recompilados). Verificado: ASC RS 26°36' con cúspide natal a 26°43' → "MC · 7' de la cúspide"; punto en casa 4 → "FC".


v3.14.20 — 2026-09-19



Corregido


  • Revolució Solar — "Angles natals a cases RS" sin DES ni FC: el metadata natal solo trae ASC y MC, así que generarAnglesNatalsACasesRS() descartaba Descendente y Fondo del Cielo (el render y las traducciones ya los soportaban). Ahora DSC = ASC+180° e IC = MC+180°. Verificado: ASC 14.28° → DES 194.28°, MC 144.28° → FC 324.28°.


v3.14.19 — 2026-09-19



Corregido


  • Síntesis inventa los miembros del stellium: con "Casa 1 (4 planetas)" sin nombres, completaba con puntos salientes ("Marte, Plutón, Venus y Nodo Sur", 3 de 4 falsos). Nuevo MaiaExport::miembrosEnfasis() (cruce ÉNFASIS × POSICIONES → "CASA 1 (4): Sol, Mercurio, Venus, Neptuno", verificado determinista) inyectado en DATOS CLAVE + regla anti-completado en la síntesis. Verificado e2e en carta real: "Casa 1 (4 planetas: Sol, Mercurio, Venus, Neptuno)", QA 5/5.


v3.14.18 — 2026-09-19



Corregido


  • Digest 1.7b confabula en exports reales (causa raíz de los errores factuales): con la carta real inventaba "Agua ausente (0%)" con Agua al 30%, "Luna en Tauro casa 1" (real: Cáncer casa 9), "Mercurio en Acuario casa 3" (intercambiado con Marte) y se contradecía en dos frases; la síntesis propagaba sus errores y el QA 5/5 no los cazaba (mide cobertura, no veracidad). Digest por defecto ahora devstral-small-2:24b (vía MAIA_DIGEST_MODEL; 1.7b elegible por env). Verificado en la misma carta: stellium, posiciones, nodos y Aire/Agua correctos, QA 5/5. Run total ~2 min.

  • Pendiente (precisión temporal): la síntesis aún puede inventar detalles de tránsitos (caso: "Júpiter cuadratura Venus + conjunción MC" inexistentes; el natal tiene Júpiter sextil MC 2.4°). El gate/QA solo verifica presencia de fechas, no su exactitud. Candidatas: lista blanca determinista de fechas o digest temporal determinista.


v3.14.17 — 2026-09-19



Corregido


  • Síntesis 30B vacía de forma sistemática: think:false no lo obedece el qwen3-vl:30b-a3b-thinking en prompts complejos (think 10k+ chars, done:length, content 0 en los 2 intentos). Probe de modelos: devstral-small-2:24b redacta directo en español (1072 chars, 29 s), qwen3.6:27b obedece think:false, qwen3:4b filtra thinking en inglés dentro del content (descartado). Nuevo modelo de síntesis por defecto: devstral-small-2:24b (vía MAIA_SYNTHESIS_MODEL; se respeta MAIA_OLLAMA_MODEL por compatibilidad; el 30B sigue elegible por env). Verificado e2e: QA 5/5.


v3.14.16 — 2026-09-19



Añadido


  • Sección CÚSPIDES DE LAS CASAS en el export (ajax/ia_export.php, tras ÃNGULOS): las 12 cúspides con grado+signo desde $datos['casas']. Ni el lector ni la IA podían saber el signo en cúspide; la síntesis confundía "punto situado en la casa" (Nodo Sur en Virgo en casa 10) con "cúspide" (casa 10 = Leo). MaiaExport::cuspidesCasas() la parsea, estructura() la incluye en la pasada 1 y cuspidesAngulares() la prefiere (fallback a ÃNGULOS para exports antiguos, verificado en ambos formatos).


v3.14.15 — 2026-09-19



Corregido


  • Síntesis 30B vacía (causa raíz): el modelo quemaba todo num_predict pensando sin redactar (traza: think 12k chars, content 0, done:length, 2 intentos). Verificado que think:false sí lo desactiva (test directo: content correcto). Digest y síntesis van sin thinking; la síntesis conserva num_predict: 3000 para redactar. Run e2e 30B (digest 1.7b): 80 s totales, contenido completo.

  • Falso negativo del QA en eje_nodal: la regex exigía literalmente "Sur en Leo" y el 30B escribió el dato correcto como "Sur: Leo, casa 10". Acepta ahora Norte:, (, - además de en (misma frase, signo y casa reales). La síntesis 30B reevaluada pasa a QA 5/5.


v3.14.14 — 2026-09-18



Corregido


  • Síntesis 30B vacía ("acaba y no muestra nada"): el modelo quemó el presupuesto pensando sin redactar; el guard lanzaba antes de registrar traza (intento invisible) y sin reintento. Ahora: la traza se registra siempre (incluso en vacío), el vacío cuenta como cobertura ausente (reintento automático) y solo si ambos intentos salen vacíos hay error visible e informativo. Verificado con stub determinista (intento 1 vacío → intento 2 OK; siempre-vacío → excepción). Causa raíz del vacío 30B pendiente de caracterizar con la próxima traza completa.


v3.14.13 — 2026-09-18



Añadido


  • Puerta de cobertura con 1 reintento: MaiaPipeline::verificarCobertura() (espejo ligero del QA: casa, nodo, orbe, fecha) tras la síntesis; si falta algo, reintento único con nudge explícito de lo omitido (máx. 2 intentos, campo intento en traza). El 4/5 intermitente del 1.7b era ruido de muestreo con prompts idénticos (dato nodal presente 2x y aun así omitido 2 veces seguidas). Verificado: intento 1 falló cobertura, intento 2 pasó → QA 5/5.


v3.14.12 — 2026-09-18



Añadido


  • Botó â¹ Aturar (MAIA AI): partes/ia_export.php mostra l'aturada mentre corre l'anàlisi; avorta el fetch (AbortController) i crida la nova acció cancel de ajax/ia_maia.php, que descarrega el model (ollama stop, nom validat + escapeshellarg, mateixos guards auth/CSRF). Allibera la GPU al moment; les passades completades queden a la traça.


v3.14.11 — 2026-09-18



Corregido


  • 504 en MAIA AI con el 30B (run real: 639 s, SIGTERM): la pasada temporal generó ~10k tokens (~377 s) para un resumen de 200 palabras; el total superó nginx (600 s) + php-fpm y el navegador solo veía JSON.parse... sobre el HTML del 504. Digest (estructura/aspectos/temporal) ahora sin thinking (think: false, Ollama ≥0.12) y con num_predict: 600; síntesis con num_predict: 2000. Las opciones quedan registradas en cada traza. Verificado: mismo export + qwen3:1.7b sigue en QA 5/5.

  • Error humano ante 504/502/500: _maiaPost() (partes/ia_export.php) ya no muestra el JSON.parse crudo; explica timeout y sugiere modelo más rápido.


v3.14.10 — 2026-09-17



Añadido


  • Export auto-guardado para QA: ajax/ia_export.php archiva cada export generado en logs/maia_ai_exports/ (protegido por .htaccess, gitignored; se conservan los 10 recientes) y devuelve export_file en el JSON. Permite QA estricto (--texto + --carta) sin copiar/pegar.


v3.14.9 — 2026-09-17



Corregido


  • Eje nodal ignorado por el modelo pequeño (QA 4/5 → 5/5): el nodo solo llegaba a síntesis una vez (línea suelta en datosClaves()); casa y aspectos llegaban reforzados desde los resúmenes. Nuevo MaiaExport::lineaNodal() (reutilizado en datosClaves()) y refuerzo determinista al final del resumen estructural en MaiaPipeline::analizarCartaNatal(). Verificado con qwen3:1.7b sobre el mismo export: 5/5 sin necesidad del 30B.


Pendiente (seguimiento)


  • Pasada estructura 10-20x más larga de lo pedido (1500-4800 tokens vs tope de 200 palabras). Si se repite con el 30B, tratar como ítem propio: erosiona la ventaja de bloques cortos antes de síntesis.


v3.14.8 — 2026-09-17



Añadido


  • Trazas con modelo: cada entrada JSONL registra modelo (nuevo OllamaMaiaClient::modelo()). Sin esto, dos runs con modelos distintos no son comparables (detectado al revisar trazas sin thinking ni duraciones de 30B).


v3.14.7 — 2026-09-17



Añadido


  • RAG, Los Luminares (Greene/Sasportas): data/maia_rag_corpus/greene_sasportas_luminares.md (libro completo: Luna/madre/matriarcado, Luna en relaciones, héroe solar, Sol/padre/yo, coniunctio, lunaciones y nodos; 332 fragmentos, tags luminares-sol-luna; índice total: 648).


Corregido


  • Trossejador RAG amb paràgrafs gegants: MaiaRagStore::trocear() parteix per frases els paràgrafs que superen el pressupost (text amb salts de línia durs, sense línies en blanc). Abans, el llibre sencer col·lapsava en 1 chunk monstruós que Ollama rebutjava (HTTP 500).


v3.14.6 — 2026-09-17



Añadido


  • RAG, Sasportas caps. 7–9 (OCR): sasportas_transitos_neptuno_pluton_ocr.md (final cap. 6 + cap. 7 Neptuno por planetas/casas + inicio Plutón; 73 fragmentos, tags sasportas-neptuno-pluton), sasportas_crisis_plutonianas_cap8_ocr.md (mito Inanna/Ereshkigal; 18 fragmentos, tags sasportas-pluton-crisis) i sasportas_transitos_pluton_cap9_ocr.md (Plutón por planetas/casas; 32 fragmentos, tags sasportas-pluton-transitos; índice total: 316). Limpieza ligera de OCR aplicada (guiones de línea, marcas inequívocas, números de página).


Corregido


  • Indexador RAG tolerante a OCR: MaiaRagStore::indexarFichero() omite (con aviso a STDERR) los fragmentos que Ollama rechaza (HTTP 500 con basura de escaneo) en vez de abortar toda la indexación. 36 fragmentos omitidos en los 3 capítulos.


v3.14.5 — 2026-09-17



Añadido


  • Corpus RAG a git (backup): data/maia_rag_corpus/ commiteado con git add -f (sigue gitignored: los ficheros nuevos futuros requieren -f). El índice data/maia_rag_index.json NO se commitea (regenerable con php scripts/maia_rag_index.php).


Seguridad


  • Docs IA nunca a staging/producción: nueva tarea Deployer deploy:purge_ai_docs (tras deploy:update_code) que borra data/maia_rag_corpus/, data/maia_rag_index.json y todos los *.md del release excepto CHANGELOG.md, ROADMAP.md y prompt-astrologia-psicologica.md (este último lo lee ajax/ia_chat.php en runtime para el botón DeepSeek). El próximo deploy elimina los docs IA ya publicados.


v3.14.4 — 2026-09-17



Añadido


  • RAG, Neptuno por las 12 casas: data/maia_rag_corpus/transito_neptuno_12_casas.md (disolución, idealización, sacrificio, marco de 7 preguntas + ejemplo casa 7; 8 fragmentos, tags transitos-neptuno).

  • RAG, Plutón por las 12 casas: data/maia_rag_corpus/transito_pluton_12_casas.md (sombra, poder, ciclo plutoniano + ejemplo casa 10 + tabla Urano/Neptuno/Plutón; 9 fragmentos, tags transitos-pluton; índice total: 193).


v3.14.3 — 2026-09-17



Añadido


  • RAG, Urano por las 12 casas: data/maia_rag_corpus/transito_urano_12_casas.md (lectura psicológica por casas + marco de 7 pasos + ejemplo casa 7; 17 fragmentos, tags transitos-urano; índice total: 176).


v3.14.2 — 2026-09-17



Añadido


  • RAG, tránsito Urano en casa 7: data/maia_rag_corpus/transito_urano_casa7.md (lectura psicológica Sasportas/Greene: proyección, individuación, eje Yo–Tú; 4 fragmentos, tags transitos-urano-casa7; índice total: 159).


v3.14.1 — 2026-09-17



Añadido


  • RAG, primer corpus real: data/maia_rag_corpus/greene_doce_casas.md (Sasportas, planetas por casas, 56 fragmentos, tags greene-casas; índice total: 69). Corpus gitignored (data/maia_rag_corpus/). Escuela de referencia: Aula Astrològica de Catalunya.

  • RAG, apunts de l'Aula: aula_fonaments_01.md (Jung, 7 principis hermètics, esfera/eclíptica, zodíac, polaritats, 4 elements + funcions junguianes; tags aula-fonaments) i aula_modalitats_02.md (cardinal/fixa/mutable + taula tècnica del zodíac; tags aula-modalitats). Ãndex total: 73 fragments.

  • RAG, nivell 1 complet: 18 PDFs + 1 DOCX de apunts_per_ia extrets a data/maia_rag_corpus/aula_nivell1/ (pypdf/pandoc; pàgines només-diagrama descartades) i indexats amb tags per tema. Ãndex total: 155 fragments.


Corregido


  • MAIA AI alucinaba el eje nodal: la síntesis citó "Nodo Norte en Cáncer / Sur en Capricornio" con los datos reales Piscis casa 4 / Virgo casa 10 delante (carta real de prueba). Nueva MaiaExport::datosClaves() (eje nodal + casa con énfasis + top-3 aspectos verificados por cálculo) inyectada en el prompt de síntesis con orden de no contradecirla. Segunda pasada con el fix: nodos correctos.

  • QA estricta: con --carta, el check nodal exige signo+casa REALES (caza la alucinación anterior) y acepta la forma corta "Norte en Piscis"; equilibrio acepta cabeceras negrita además de # y numeradas.

  • Timeouts para el 30B thinking: cada pasada puede superar 5 min en local → CURLOPT_TIMEOUT 300 → 1800 en OllamaMaiaClient y set_time_limit(0) en ajax/ia_maia.php durante el pipeline.


v3.14.0 — 2026-09-17



Añadido


  • MAIA AI, rúbrica QA (scripts/qa_maia.php, Fase 6 del plan): 5 comprobaciones deterministas sobre la síntesis (casa con énfasis, NN signo+casa, orbe numérico, fecha tránsito/progresión, equilibrio de secciones). Usos: --texto + --carta, stdin, o --carta (ejecuta el pipeline). Exit 0/1 para CI. Referencia actual con qwen3:1.7b: 4/5 (falla eje nodal; el 30B debe clavar 5/5).

  • MAIA AI, RAG ligero (includes/MaiaRagStore.php, Fase 4): índice JSON en data/maia_rag_index.json (gitignored, regenerable), chunks ~350 palabras con solape, embeddings nomic-embed-text vía Ollama, coseno en PHP (sin dependencias: sqlite-vec/Chroma innecesarios para este volumen). Indexador scripts/maia_rag_index.php (corpus inicial: prompt-astrologia-psicologica.md, 13 fragmentos). MaiaPipeline acepta RAG opcional e inyecta 2 fragmentos por pasada temática; ajax/ia_maia.php lo activa solo si hay índice. Sin índice, comportamiento idéntico al anterior.


v3.13.0 — 2026-09-17



Añadido


  • MAIA AI, pasada temporal: el pipeline ahora integra el momento actual. MaiaExport::progresionEdadActual() extrae del bloque PROGRESIONES solo el año de vida actual; transitos() ordena lentos primero y topa a 40 líneas. Nueva MaiaPipeline::pasadaTemporal() (ventana hoy−1m/hoy+6m + progresión actual, máx 200 palabras) y la síntesis integra 3 resúmenes (natal + aspectos + temporal) con punto 5 "cómo el momento actual dialoga con el tema central". Detección automática de la fecha de nacimiento desde la cabecera del export (MaiaExport::fechaNacimiento()); MaiaChatSession guarda también el contexto temporal. Si no hay material temporal, la pasada se omite y todo sigue como antes.

  • MAIA AI, checklist obligatorio en síntesis (Fase 1 del plan): casa con énfasis, eje nodal (signo+casa), 2-3 aspectos con orbe y pregunta abierta de cierre. num_ctx 16384 → 32768.

  • Fix natal+residencia: con las dos cartas marcadas, MaiaExport se quedaba con las subsecciones de residencia (last-wins). Ahora first-wins (nacimiento).


v3.12.0 — 2026-09-16



Añadido


  • MAIA AI local (Ollama): el botón "Enviar a MAIA AI" del panel de export para IA ahora envía el TEXTO del export (que ya incluye Balance Astral, planetas influyentes, énfasis y fase lunar) en vez del JSON datos. Nuevo pipeline en 3 pasadas (estructura → aspectos → síntesis psicológica) con trazas JSONL para auditoría. Nuevas clases en includes/: OllamaMaiaClient (con disponible() y config vía MAIA_OLLAMA_URL/MAIA_OLLAMA_MODEL), MaiaExport (parseo del texto + conteo determinista de aspectos por punto), MaiaPipeline (orquestación + trazas), MaiaChatSession (chat de seguimiento en disco con TTL 4h). ajax/ia_maia.php reescrito sobre este motor (auth/CSRF con el patrón de ia_export.php, sesiones y trazas en logs/, guard "solo en local" si Ollama no responde). El endpoint antiguo (datos → scripts/maia_server.py, inexistente) queda sustituido. Nota: marcar a la vez "natal (naixement)" y "natal (residència)" genera dos bloques con las mismas subsecciones y el parser se queda con el último — para MAIA AI, generar solo con "naixement" de momento.

  • Export para IA: salto de línea faltante entre Cuadrantes y PLANETAS MÃS INFLUYENTES (y lo mismo en ÉNFASIS/FASE LUNAR cuando no hay planetas influyentes) — ├── quedaba pegado al final de la línea anterior y el parser lo tragaba dentro de la sección previa. Añadido \n inicial en ajax/ia_export.php.


v3.11.6 — 2026-09-09



Corregido


  • Búsqueda de ciudades (/api/v1/geo/search) lentísima / MySQL al 100% CPU: la query usaba LIKE '%...%' con comodín inicial sobre name, asciiname, alternatenames (+ city_translations) → full scan de ~5M de filas en cada pulsación (8-12s por búsqueda). Reescrita a UNION por prefijo (name LIKE 'q%', asciiname LIKE 'q%', city_translations LIKE 'q%' + rama FULLTEXT BOOLEAN solo con 4+ caracteres), cada rama ORDER BY population DESC LIMIT 8 y enriquecimiento (admin1/país/traducción) solo sobre ≤32 candidatos. Resultado: 2-100ms. El fallback "ciudad más cercana" (modo edición) usaba ORDER BY dist sobre todas las ciudades con population > 5000 → ahora caja envolvente ±1° (±5° si vacía) con USE INDEX (idx_lat_lon). Nueva migración 024_geonames_search_perf.sql con el índice idx_lat_lon (latitude, longitude). Formato de respuesta JSON sin cambios.


v3.11.5 — 2026-09-08



Añadido


  • Aviso de nuevo usuario a "Rei do Mambo": al crear una cuenta (AuthManager::register(), cubre registro normal y SSO) se envía un email a cada usuario no bloqueado del grupo "Rei do Mambo" con nombre, email, ID y fecha de registro del nuevo usuario. Envío no bloqueante (fallos SMTP solo se loguean). Nuevo método EmailService::sendNewUserNotification().


v3.11.4 — 2026-08-23



Corregido


  • Aspectos a los ángulos en el informe: los aspectos a Ascendente/Medio Cielo/Descendente/Fondo del Cielo aparecían sin nombre (ej. "Quincuncio a (…)", "Trígono a (…)"). AstrologiaHelper::getTranslate() no resolvía las claves de ángulo del AspectosCalculator (Ascendant, Midheaven, Descendant, IC) → añadidas las constantes TRANSLATE_ASCENDANT/MIDHEAVEN/DESCENDANT/IC. Ahora se muestran como "Ascendente", "Medio Cielo", "Descendente", "Fondo del Cielo". El fix es central: aplica también al grid de aspectos y a la rueda.


v3.11.3 — 2026-08-23



Añadido


  • Nueva clase includes/FuncionInferiorCalculator.php (doc 03 §01–§03): detecta funciones inferiores por los criterios de elemento único, modalidad única y grado 29°, con la excepción transpersonal (Urano/Neptuno/Plutón/Quirón solo cuentan como representantes si aspectan a un planeta personal/social). Universo: Sun–Quirón.


Corregido


  • Card de planeta en el informe: un planeta que sea el único en su elemento o modalidad (ej. la Luna como único planeta de Fuego a 3° Aries, carta de Anais Mateo) ahora se marca como "Función inferior (elemento único)" / "(modalidad única)", no solo cuando está a 29°.

  • Traducciones (7 idiomas): claves "Función inferior (elemento único)" y "Función inferior (modalidad única)".


v3.11.2 — 2026-08-21



Corregido


  • Roadmap (/admin/roadmap): el renderizador Markdown propio no soportaba ~~strikethrough~~ → se mostraba ~~texto~~ literal en vez de tachado. Ahora ~~ → <del> (inline y en items de lista, conservando numeración/viñetas).

  • Roadmap: parseRoadmap solo reconocía pending|done → las secciones in_progress (cobro y suscripción, gestor de email) se incrustaban dentro del item "Realizado" anterior. Ahora se parsean como tarjetas propias con badge "🔨 En curso" e incluidas en la pestaña Pendientes (contador + índice).


Cambiado


  • Roadmap: nueva sección "Pendientes" consolidada arriba del documento (<!-- status: pending -->, visible en la pestaña Pendientes) con los pendientes reales movidos desde las secciones en proceso (promotores, IVA, prorrateo, audit log, hardcodeos, emails) y todo lo ya realizado tachado en cada sección.


v3.11.1 — 2026-08-21



Corregido


  • Modal: el .modal-content legacy de styles.css capaba el ancho a 500px; override en .modal-dialog .modal-content (max-width: none, width: 100%, font-size: 16px). El modal large passa a width: 95% (més ample, sense cap de 900px).

  • Gestor email — prova de connexió: admin/email-config.php no definia $user (email de prova buit) i EmailService::send() referenciaba $isHTML no inicialitzada al catch. Corregit.

  • Reply-To: camp "Email de resposta" a la config (per defecte = email d'enviament) aplicat a tots els enviaments.

  • DotEnv: les variables ara es sobreescriuen en carregar .env → els canvis guardats des del panel admin (email, Stripe…) tenen efecte immediat encara que la variable ja existeixi a l'entorn del procés PHP-FPM.

  • Viewer d'email: fonts mínim 16px (abans 12px).


v3.11.0 — 2026-08-21



Afegit — Gestor de email


  • Configuració SMTP a l'admin (/admin/email-config): host, port, xifrat SSL/TLS, usuari, password, email i nom d'enviament. Guarda a .env + botó "Guardar i provar connexió" (envia email de prova).

  • Registre automàtic de tots els emails (email_logs): data/hora, destinatari, assumpte, cos HTML/pla, estat (sent/failed) i missatge d'error. Central a EmailService::send() (no bloquejant).

  • Llistat admin (/admin/email-logs): paginat, amb accions Veure (popup 90% amb format de mail), Reenviar (tal qual) i Borrar.

  • Migració: migrations/add_email_logs_table.sql.

  • Card "📧 Email" al panell admin i enllaços entre configuració i registre.

  • ROADMAP: redactar manualment i editar abans de reenviar com a pendents a futur.


v3.10.1 — 2026-08-21



Corregido


  • Reemborsament de subscripcions: el botó "Reemborsar" de tesoreria fallava amb "No such payment_intent" perquè les transaccions de suscripció guardaven l'id de sessió (cs_...) en lloc del PaymentIntent (pi_...). Ara resolvePaymentIntent() resol el pi_ real (pago inicial del client) tant al reemborsar com al guardar la transacció i a la cancel·lació amb reembors.

  • my-transactions: el modal de cancel·lar subscripció sense l'emoji â›” al títol i amb size: large.


v3.10.0 — 2026-08-21



Afegit


  • Síntesi del balance al final del bloc Balance Astral (gated pel permís view_sintesis_balance).

  • Nova síntesi d'hemisferis i quadrants (SintesisHemisferios) al final del bloc Hemisferis i quadrants (gated pel mateix permís): dominants vertical/horizontal + quadrants amb frases.

  • Consell de la fase lunar (al final de la targeta de la Lluna) i frase de Quiró + afirmacions (al final de la targeta de Quiró): només es mostren si el permís està activat.

  • Permís renomenat: "Mostrar Síntesis Balance Astral" → "Mostrar Síntesis en informe" (BD + traduccions 7 idiomes).

  • Pàgina /my-subscription: estat unificat de la subscripció (pla, caducitat, ús de cartes amb barra de progrés, cancel·lar subscripció, enllaç a historial de pagos i upgrade).


v3.9.0 — 2026-08-21



Cobro i subscripcions (Stripe Subscriptions)


  • Suscripcions recurrents: el checkout de Stripe ara funciona en mode=subscription (preus monthly/annual). Stripe guarda la targeta (Customer + PaymentMethod) i cobra automàticament; l'app no toca mai dades de targeta.

  • Webhooks nous a ajax/stripe-webhook.php: invoice.paid (renova i estén la caducitat), invoice.payment_failed (email d'avís), customer.subscription.deleted (downgrade al grup fallback).

  • Cancel·lació des de Maia: botó "Cancel·lar subscripció" a /my-transactions. Mensual → cancel·la al final del període ("activa fins al X"). Anual → 2 opcions: cancel·lar al final o cancel·lar ara i reemborsar (reembors del darrer pagament + downgrade).

  • Cupons: en subscripcions, el descompte s'aplica a la primera factura (cupó Stripe de durada once).

  • Fix stacking anual: PaymentEngine::extendExpiration() suma la durada amb la unitat correcta (dies/mesos/anys); abans INTERVAL ? MONTH no funcionava per al pla anual (1 any).

  • Migració: migrations/add_stripe_subscription_columns.sql — stripe_customer_id, stripe_subscription_id a usuarios.

  • Preus: $8,5/mes (850¢) i $72/any (7200¢) → ≈ 3 mesos gratis en el pla anual.


Afegit


  • Eliminat Square per complet: eliminats SquarePayment.php, ajax/square-webhook.php, ruta i variables SQUARE_* del .env.example. El motor comú passa a includes/PaymentEngine.php (usat per Stripe).

  • Permisos en 4 seccions a admin/group_edit.php: Permisos Asignados, de Administrador, Avanzados i para IA.

  • Banner Free al dashboard (grups is_free) amb preus USD/EUR (canvi actual, anual ÷12) i llista de funcions desbloquejades per permisos.

  • Tooltip a les cartes bloquejades per quota (segueix el cursor, clic → /upgrade).

  • /upgrade: preus en euros al canvi actual + llista de diferències vs pla actual + "≈ N mesos gratis" al pla anual.

  • Traduccions: texts del banner, tooltip, upgrade i els 16 permisos traduïts als 7 idiomes; corregides cadenes que sortien en castellà quan l'idioma era català.


Corregido


  • Enllaços .php físics (404 en producció perquè el servidor enruta tot pel front controller): corregits a admin/*, charts/*, partes/header.php per usar route().

  • CLI maia: migracions aplicades correctament (columna filename, comentaris --).


v3.8.0 — 2026-08-21



Afegit


  • Reemborsament des de tesoreria: botó "â†©ï¸ Reemborsar" a cada transacció completada de Stripe a admin/treasury.php. Nou endpoint ajax/refund-payment.php (admin + CSRF) que reemborsa via Stripe API (Refund::create amb el payment_intent).

  • Rollback de subscripció en reemborsar: SquarePayment::rollbackSubscription() (extret de processRefund) baixa l'usuari al grup fallback si segueix al grup del pla; StripePayment::refundTransaction() el crida automàticament.

  • Ruta Router::post('/ajax/refund-payment', ...).


v3.7.2 — 2026-08-21



Corregido


  • Premium no se activaba tras el pago: los planes (subscription_prices) tenían group_id = NULL y no existía grupo Premium en user_groups, por lo que aplicarPlanYCupon() no asignaba grupo. Nueva migración add_premium_groups.sql que crea los grupos Premium Mensual (1 mes) y Premium Anual (1 año), con fallback a Users, y los vincula a los planes monthly/annual.


v3.7.1 — 2026-08-21



Corregido


  • Webhook de Stripe inaccesible en producción: el servidor (nginx) enruta todo por el front controller y las rutas van sin .php. Añadidas las rutas Router::post('/ajax/stripe-webhook', ...) y Router::post('/ajax/stripe-webhook.php', ...).

  • URL correcta del webhook: https://astro.omda.es/ajax/stripe-webhook (la app corre en astro.omda.es, no en omda.es). Actualizar la URL del endpoint en el dashboard de Stripe (el whsec_ no cambia).


v3.7.0 — 2026-08-21



Cobro con Stripe (sustituye a Square)


  • Stripe Checkout: nuevo includes/StripePayment.php (SDK stripe/stripe-php v21) que crea sesiones de checkout alojado con tarjeta. ajax/create-checkout.php ahora redirige a Stripe; ajax/stripe-webhook.php procesa checkout.session.completed (firma verificada, fail-closed).

  • Activación de premium reutilizada: handleCheckoutCompleted() usa aplicarPlanYCupon() (idempotente, update atómico condicional) + emails de confirmación/bienvenida ya existentes.

  • Moneda USD: precios 6,5$/mes (650¢) y 78$/año (7800¢); STRIPE_CURRENCY en .env. Visualización de upgrade.php y my-transactions.php en $.

  • Migración: migrations/add_stripe_provider.sql — columnas provider y provider_payment_id en payment_transactions + actualización de precios a USD.

  • Tesorería: columna de proveedor (💳/🧾) y CSV con proveedor e ID de pago; estado refunded en el mapa.

  • Retorno: dashboard.php muestra confirmación al volver de Stripe (?paid=stripe); la activación real la hace el webhook.

  • Config: claves en .env → STRIPE_SECRET_KEY, STRIPE_PUBLISHABLE_KEY, STRIPE_WEBHOOK_SECRET, STRIPE_CURRENCY=USD. Crear endpoint de webhook en Stripe apuntando a /ajax/stripe-webhook.php (evento checkout.session.completed).

  • CLI maia corregido: usaba la columna migration (inexistente; la tabla usa filename) y descartaba bloques SQL cuyo primer bloque empezaba por comentario --. Ahora php maia migrate funciona con los .sql existentes.


v3.6.0 — 2026-08-21



Cobro y suscripción — revisión (roadmap punto 1)


  • Anti-doble-cobro (idempotencia): completePayment() no reprocesa transacciones no-pendientes y usa update atómico condicional (WHERE status='pending'). completeFromRedirect() y completePayment() comparten aplicarPlanYCupon().

  • Cupones de extensión en redirect: completeFromRedirect() ahora aplica cupones extension (antes solo el webhook).

  • Email de confirmación de pago: EmailService::sendPaymentConfirmation() (plan, importe, caducidad, referencia). Se envía al completar el pago (redirect o webhook).

  • Email de bienvenida premium: EmailService::sendPremiumWelcome().

  • Email de aviso de caducidad: EmailService::sendExpiryWarning() disparado desde AuthManager::checkGroupExpiration() con notice_days del plan y throttling de 1/día (columna expiry_warning_sent_at).

  • Limpieza de transacciones stale: SquarePayment::cleanupStaleTransactions() (pending → abandoned), ejecutada en dashboard.php máx. 1 vez/hora.

  • Reembolsos: el webhook maneja refund.updated → processRefund() marca refunded y revierte el grupo al fallback.

  • Export CSV de tesorería: botón en admin/treasury.php con filtro de estado aplicado.

  • Migración: migrations/add_expiry_warning_sent_at.sql (expiry_warning_sent_at en usuarios). Aplicar con php maia migrate o panel admin.


v3.5.0 — 2026-08-20



Afegit


  • MAIA AI local (interpretació amb Ollama): nou botó «🧠 Enviar a MAIA AI» a la pestanya IA, que envia el JSON estructurat de la carta a un motor Python local (~/Proyectos/astrologia-ai) i mostra la interpretació (Part 1 tècnica + Part 2 psicològica) sense dependre de DeepSeek.

- ajax/ia_maia.php: proxy que reenvia el JSON al servidor local. URL configurable amb MAIA_AI_URL (per defecte http://127.0.0.1:8765/chat).
- partes/ia_export.php: botó nou «Enviar a MAIA AI» + missatges d'estat.
  • Chat multi-torn amb MAIA AI: el servidor local manté sessió (POST /chat amb {datos} o {session_id, mensaje}) i la pestanya IA mostra un xat amb historial, camp de pregunta i botó «Nova conversa». L'usuari pot fer preguntes de seguiment sobre la carta enviada.

  • Camp datos JSON a l'export IA: ajax/ia_export.php ara retorna {success, texto, datos} amb la carta estructurada (planetes amb casa, casas, ángles, aspectes ordenats per orbe, balanç en espanyol, patrons). Botó «💾 Exportar JSON» per descarregar-lo (maia_carta_<id>.json).

  • Documentació: documentation/maia_ai_local_module.md amb el contracte de dades, el flux i les instruccions d'arrencada del servidor local.


v3.4.1 — 2026-08-20



Seguretat (ronda 2 — re-scan Strix)


  • Escalada de privilegis a "Rei do Mambo" (CWE-269): admin/users.php ara només permet assignar el grup "Rei do Mambo" si l'actor autenticat en forma part.

  • XSS reflectat (CWE-79): logs/index.php escapa view a l'href; api/v1/update/check.php serveix JSON amb Content-Type correcte i JSON_HEX_*.

  • Stored XSS per nom d'usuari (CWE-79): js/share-manager.js nou helper jsAttrEscape() per onclick + escapeHtml() als sinks innerHTML del modal.

  • Payment bypass (CWE-841): SquarePayment::completeFromRedirect() ara verifica amb Square que el payment és COMPLETED abans d'activar premium (no confia en ?paid=1).

  • CSRF (CWE-352): afegit csrf_token a admin/migrations.php, ajax/translations.php i ajax/create-checkout.php (+ forms/JS).

  • .env i dotfiles: .htaccess raíz denega dotfiles i composer/package; vendor/.htaccess Require all denied.

  • Rate limiting PII: api/v1/chart/logs.php limitat per API key+IP (60/10min).

  • Token Square: eliminat el token sandbox de .env.example.


Seguretat (ronda 1)


  • SSO auth bypass (CRÃTIC): el secret sso_secret es reutilitzava com a X-API-Key del plugin carta-natal-maia (exposat al client JS) i com a secret de signatura SSO. Ara els endpoints SSO (auth/sso_login.php, api/sso_generate.php) i el consumidor de sso_token (partes/RequireLogin.php) només accepten llocs amb plugin_type = 'maia' (secret només al servidor), blocant el forjat de tokens amb el key exposat.

  • Dependència vulnerable: league/commonmark actualitzat de 2.7.1 → 2.10.0, resolent 4 CVEs (DoS per complexitat algorítmica + 3 XSS/bypass). Verificat amb composer (sense advisories restants).

  • Password reset — link poisoning via Host (CWE-640): generateResetLink() ara construeix l'enllaç des de APP_URL (config) en lloc del header Host, i apunta a /reset-password.

  • Password reset — filtrado de token (CWE-522): requestPasswordReset() ja no retorna el reset_link; eliminat el bloc "mode desenvolupament" que el mostrava.

  • Password reset — enumeració de comptes (CWE-203): resposta genèrica tant si l'email existeix com si no.

  • Password reset — flux trencat corregit: auth/reset.php usava $pdo global indefinit i comparava el token cru contra el hash SHA-256. Ara usa findByResetToken()/resetPassword() del repositori.

  • Fuerza bruta en login (CWE-307): nova classe includes/RateLimiter.php (contadors per IP+email en logs/rate_limits/). AuthManager::login() limita a 5 intents fallits per IP+email en 15 min i reseteja en loguejar.

  • Rate limiting en forgot-password (CWE-307): requestPasswordReset() limita a 5 peticions per IP+email en 15 min.

  • XSS reflectat (CWE-79): partes/transitos.php volcava $_GET['id'] sense escapar; ara usa (int)($_GET['id'] ?? 0).

  • IDOR en compartir (CWE-639): charts/share.php get_shared llistava usuaris compartits sense comprovar propietat; ara comprova esPropietario() abans.

  • CSRF en compartir (CWE-352): charts/share.php ara verifica csrf_token abans de cada acció; js/share-manager.js envia el token (meta csrf-token) a totes les peticions.

  • Stored XSS per nom de carta (CWE-79): charts/view.php:563 usava addslashes() en context JS → ara json_encode(). Corregits també els vectors a dashboard.php (onclick de compartir/eliminar) i els sinks innerHTML del modal (share-manager.js, confirmDeleteCarta).

  • Webhook Square (CWE-347): ajax/square-webhook.php ara és fail-closed: sense SQUARE_WEBHOOK_SIGNATURE_KEY configurada retorna 503 i no processa; amb clau, la verificació de firma és obligatòria.

  • CSRF en admin (CWE-352): verificació de csrf_token + camp ocult als formularis de admin/groups.php, admin/group_edit.php, admin/treasury.php i admin/coupons.php.

  • Accés no autenticat a logs/scripts (CWE-306/CWE-532): afegit Require all denied a scripts/, config/ i sql/; gate CLI a scripts/__install.php i scripts/generador_ephemeris.php; logs/index.php ara requereix access_admin_panel.


v3.4.0 — 2026-08-16



Afegit


  • Text per a IA (export) ampliat: abans de les posicions planetàries, ara s'inclou tota la informació de l'informe:

- Àngles principals (ASC, MC, DSC, IC) amb grau i signe.
- Balanç astral (elements, modalitats, polaritats i dominant).
- Hemisferis i quadrants (corregides les claus numèriques que no mostraven res).
- Planetes més influents (via CalculadorInfluenciaPlanetas) amb puntuació i raons.
- Èmfasi en cases i signes (3 o més planetes).
- Fase lunar (separació Sol-Lluna).
  • Pestanyes a les Direccions d'Arc Solar (includes/DireccionesCalculator.php): ara els resultats es mostren en dues pestanyes, com a progressions i trànsits:

- 📊 Direccions Detallades: la taula que ja existia.
- 📋 Texte: llistat en text pla amb botó "Copiar al portapapeles" (aspectes i ingressos amb edat, data, planeta, posició i orbe).
- Nous mètodes renderPestanyes(), renderTextoPlano() i formatEdat().
  • Opció "Direccions" a l'export per a IA (partes/ia_export.php + ajax/ia_export.php): nou checkbox amb rang "des de / fins a" (anys) situat abans de "Revolucions solars". Genera una secció "DIRECCIONES DE ARCO SOLAR" amb el text pla de les direccions (conjunció+oposició, 12 cases i 12 signes). renderTextoPlano() passa a ser públic.


Corregido


  • ajax/ia_export.php: hemisferios/cuadrantes usaven claus errònies (Norte, Cuadrante I) i no imprimien res; ara usen les claus numèriques correctes. També corregit el llistat de "Planetes angulares" i afegits els "Signes amb èmfasi" a la secció Informe.

  • ajax/ia_export.php: fix bug de variable sobrescrida. El foreach ($angPlanetas as $angulo => $datos) de "Planetes angulares" reemplaçava la variable global $datos (les dades de la carta) per l'últim angle (IC). Això trencava les seccions Trànsits (warning "Undefined array key planets") i Progressions (warning "array offset on float" a AspectosCalculator) i embrutava la resposta JSON amb HTML de warnings. Renombrada la variable del bucle a $angDatos.


v3.3.4 — 2026-08-11



Afegit


  • Gestor de traduccions a admin (admin/translations.php): pàgina per revisar, editar i gestionar traduccions sense tocar fitxers .po manualment.

- Cards amb % de cobertura per als 7 idiomes.
- Taula paginada amb cerca, filtres per estat (traduït/fuzzy/buit) i selecció d'idioma.
- Modal d'edició amb msgid (readonly) i msgstr editable.
- Accions en lot: aprovar totes les fuzzy, recompilar tots els .mo.
- Classe includes/TranslationManager.php: parser/editor de .po + compilador msgfmt.
- Endpoint ajax/translations.php amb accions list, save, stats, approve_fuzzy, recompile.
- Permís manage_translations (grup "Rei do Mambo").
- Card 🌠Traduccions al dashboard admin (condicionada al permís).

Corregido


  • 404 divertida: pàgina d'error amb il·lustració SVG animada (Saturn confós, Júpiter/Lluna/Sol detectius), fons clar, layout full-width, text traduït als 7 idiomes, botó "Tornar a l'inici".

  • Migrations idempotents: add_edit_content_texts_permission.sql i add_ia_export_permission.sql canvien INSERT per INSERT IGNORE.


v3.3.3 — 2026-08-10



Corregido


  • Cerca de ciutats amb traduccions: nova taula city_translations (geoname_id, lang, name) amb 159 ciutats × 7 idiomes. api/v1/geo/search.php fa JOIN amb city_translations segons el lang de la petició. Scoring simplificat: exact match (original o traduït) > té traducció > sense traducció, ordenat per població. Resultats:

- display_name i address.city en l'idioma de l'usuari (ex: "Roma, Lazio, Italia" per a lang=es)
- name amb el nom original (ex: "Rome")
- Cerca "Roma" en català/castellà troba Roma (Itàlia) com a primer resultat
  • JS passa l'idioma a l'API: script.js (cerca naixement i residència) i revolucio-solar-js.php llegeixen document.documentElement.lang i l'afegeixen com a &lang= a la petició.

  • Selector de idioma: la funció changeLanguage() definida a js/script.js sobrescrivia la del header.php al carregar-se després (al footer). La de script.js només posava una cookie i recarregava sense canviar el path, fent que el Router tornés a l'idioma per defecte. Eliminada la duplicada de script.js.

  • Idioma per defecte: canviat d'espanyol (es) a català (ca) a .env (DEFAULT_LANGUAGE=ca) i al fallback de header.php.

  • Router.url(): ara sempre afegeix el prefix d'idioma a les URLs (abans només ho feia per idiomes diferents del predeterminat). Eliminada la condició $currentLang !== $defaultLang per mantenir consistència amb changeLanguage().

  • 404 al canviar idioma al login: corregit al alinear el comportament de Router.url() i changeLanguage(). Les URLs ara sempre inclouen prefix d'idioma. També corregides les redireccions antigues (/auth/login.php, /UserLogin.php) per route('/login') a RequireLogin.php, AuthManager.php, logout.php, forgot-password.php i reset.php.


Afegit


  • migrations/023_create_city_translations.sql: taula city_translations

  • data/city_translations.json: 159 ciutats amb traduccions en 7 idiomes

  • scripts/import_city_translations.php: script d'importació per lot


Traduït


  • Todos los textos hardcoded a catalán: ~20 archivos PHP editados para cambiar texto fuente de castellano a catalán y envolverlo en __() o _e().

  • Archivos de traducción regenerados: nuevo messages.pot con 1504 cadenas extraídas de todo el código. Los 7 archivos .po actualizados con msgmerge y compilados a .mo.

  • Traducciones por idioma: ca_ES (1503, fuente=catalán), es_ES (1200 + 303 fuzzy), en_US (1200 + 303 fuzzy), fr_FR (1244 + 259 fuzzy), de_DE (1244 + 259 fuzzy), it_IT (1244 + 259 fuzzy), pt_PT (1244 + 259 fuzzy). Las cadenas no traducidas muestran el texto fuente (catalán) como fallback.


Archivos modificados


  • auth/reset.php: todos los textos a catalán + __()

  • auth/sso_login.php: mensajes die() a catalán + __()

  • auth/change-password.php: placeholders a catalán

  • auth/register.php: placeholders a catalán

  • charts/edit.php: página completa a catalán + __()

  • charts/process.php: mensajes de error a catalán

  • charts/share.php: mensaje de error a catalán

  • partes/ia_export.php: 17 cadenas a catalán + __(), JS usa variables PHP

  • partes/header.php: fallback idioma es → ca

  • admin/ai-config.php: 6 etiquetas a catalán + __()

  • admin/index.php: 4 títulos con emojis a __(), 2 descripciones a catalán

  • admin/integrations.php: opciones <select> a catalán

  • admin/roadmap.php: 3 etiquetas a catalán

  • admin/textos.php: 3 cadenas JS a catalán vía <?= __() ?>

  • includes/Router.php: 404 a catalán, prefijo idioma siempre presente

  • includes/TransitosCalculator.php: 2 mensajes vacíos a catalán

  • includes/AspectosCalculator.php: 3 etiquetas a catalán

  • includes/AspectosGridGenerator.php: título a catalán

  • includes/RevolucioSolarCalculator.php: prefijo Error: a __()

  • ajax/main.php: 10 mensajes de error a catalán + __()

  • ajax/user-transactions.php: 2 mensajes a catalán

  • ajax/transitos.php: mensaje de error a catalán

  • ajax/ia_export.php: mensaje de error a catalán

  • ajax/composite.php: 9 title de tabla a catalán

  • api/v1/chart/calculate.php: 3 etiquetas a catalán

  • js/script.js: eliminada función changeLanguage() duplicada

  • .env: DEFAULT_LANGUAGE=es → ca


v3.3.2 — 2026-08-10



Corregido


  • Planetas más influyentes en relocalización: la pestaña de residencia ahora recalcula CalculadorInfluenciaPlanetas con los datos relocalizados (ASC, casas y regentes distintos). Antes solo se calculaban para la carta natal, ignorando que la relocalización cambia el regente del ASC. Nueva sección â­ Planetas más influyentes (Residencia) en la pestaña ðŸ“.


v3.3.1 — 2026-08-10



Corregido


  • Hemisferios y cuadrantes mal calculados: CartaNatalCalculator::procesarCasas() anteponía el ASC (duplicando H1) y perdía la clave absoluto, provocando que todos los planetas se asignaran a casas incorrectas. También se corrigió la ordenación de casas en Functions.php (uksort → ksort SORT_NATURAL) y en el script Python (que las devolvía en orden H1,H10,H2...).

  • Gráficos de hemisferios con posiciones incorrectas: InformeHemisferios::dibujarCirculo() usaba ángulos que no compensaban la resta de 90° de polarToCartesian. Corregidos los 4 tipos de gráfico (Interior/Exterior, Autonomía/Relación, Cuadrantes, Viaje Conciencia). Las líneas divisorias también estaban intercambiadas (horizontal ↔ vertical).

  • Agrupaciones del Viaje de la Conciencia: el cuarto gráfico usaba casas 1-4, 5-8, 9-12 en lugar de 12+1+2+3, 4-7, 8-11.

  • Orden visual de los gráficos: intercambiados los dos primeros para que Interior/Exterior aparezca primero (con orientación N/S) y Autonomía/Relación segundo (E/O).

  • Caché de sesión: claves forzadas a v4 para evitar datos antiguos. view.php detecta datos estancados (>12 casas o sin absoluto) y fuerza recálculo.


Cambiado


  • Permiso access_ia_export: asignado a 4 grupos (Administrators, Rei do Mambo, Usuario registrado, Aula Astrológica).


v3.3.0 — 2026-08-07



Añadido


  • AI Config en Admin (admin/ai-config.php): formulario para configurar la API Key de DeepSeek. Se guarda en .env como DEEPSEEK_API_KEY. Visible para todos los admins. Nueva card en panel admin.

  • Enviar a la IA: botón 🤖 Enviar a la IA en la pestaña IA de carta natal. Toma el prompt del sistema desde prompt-astrologia-psicologica.md, adjunta el texto generado, y lo envía a DeepSeek (deepseek-chat). La respuesta se renderiza con formato MD (negritas, itálicas, listas, encabezados). Nuevo endpoint ajax/ia_chat.php.


v3.2.0 — 2026-07-28



Añadido


  • Pestaña 🤖 IA (Texto para IA): nueva pestaña en la ficha de carta (permiso access_ia_export). Genera texto estructurado para enviar a un GPT especializado en astrología psicológica. 6 secciones configurables con selectores de período:

- Carta natal (nacimiento y residencia): posiciones planetarias, ASC/MC, balance astral (elementos, modalidades, polaridades, hemisferios, cuadrantes), aspectos mayores ordenados por orbe, nodos lunares.
- Informe astral: desglose de elementos/modalidades/polaridades con planetas, hemisferios, cuadrantes, casas con énfasis, planetas angulares, fase lunar.
- Tránsitos (por defecto 5 años atrás → 5 adelante): lista cronológica con cambios de casa (casa X).
- Progresiones (mismo rango): vía ProgressionsCalculator, extracto del texto plano.
- Revoluciones solares (por defecto 2 años atrás → 2 adelante): posiciones + ASC/MC para cada año.
  • Selectores de período: cada sección dinámica (tránsitos, progresiones, RS) tiene selectores de año desde/hasta, configurables por el usuario.

  • Cambios de casa en tránsitos (normales y compuestos): al saltar de casa el planeta en tránsito, se muestra (casa N) en la línea de texto.


Cambiado


  • TransitosCalculator::adaptarResultadoPython(): añadido transito_longitud al array de salida para detectar cambios de casa.

  • TransitosCalculator::renderTextoPlano(): ahora incluye (casa N) cuando el planeta transitante cambia de casa.

  • ajax/composite.php (tránsitos compuestos): tabla HTML con símbolos planetarios, signos zodiacales, pestañas Tabla/Texto, botón copiar, cambios de casa.


v3.1.0 — 2026-07-28



Añadido


  • Tránsitos sobre la carta compuesta: nueva sub-pestaña 🔄 Tránsitos dentro de la pestaña Compuesta. Selector de fecha inicio, duración y planetas en tránsito. Reutiliza TransitosCalculator y scripts/calculadora_transitos.py sin modificaciones — los datos del composite se pasan como si fueran una carta natal. Cache en sesión por combinación de parámetros. Nueva acción calculate_transits en ajax/composite.php.

  • Progresiones sobre la carta compuesta: nueva sub-pestaña â³ Progresiones. Calcula progresiones secundarias a partir de la fecha virtual del composite (midpoint de las fechas natales). Selector de fecha de referencia y duración. Reutiliza ProgressionsCalculator y scripts/calculadora_sweph_batch.py. Nueva acción calculate_progressions en ajax/composite.php.

  • Cache de datos crudos del composite: se almacenan en $_SESSION["composite_raw_{id1}_{id2}"] los $datos crudos (no solo el HTML renderizado), permitiendo que tránsitos y progresiones puedan usar la carta compuesta como input natal.


Cambiado


  • ajax/composite.php: soporta 3 acciones (calculate_composite, calculate_transits, calculate_progressions). +100 líneas.

  • partes/composite.php: añadidas sub-pestañas y formularios de selección para tránsitos y progresiones.

  • js/composite.js: nuevas funciones calcularTransitosCompuesta() y calcularProgresionesCompuesta(). Limpieza de resultados anteriores al cambiar de carta2.

  • css/composite.css: estilos para los formularios de selección de fecha/duración.


v3.0.2 — 2026-07-28



Añadido


  • Panel de Textos de Información en Admin (admin/textos.php): editor visual por campos con previsualización en vivo (panel derecho). Cada sección tiene formularios adaptados a su estructura: inputs para textos cortos, textareas para descripciones, tags editables (contenteditable) para arrays de palabras clave/frases. Soporta 6 tipos de datos: Balance Astral, Hemisferios, Tablas de Coherencia, Fases Lunares, Quirón por Signo, y Síntesis del Balance. Permiso edit_content_texts. Guardado vía JSON a data/.

  • Sistema de datos externalizados: nuevo helper JsonDataLoader.php con caché estática por request. Las clases consumidoras (TooltipData, InfoAstrologica, SintesisBalance) leen de archivos JSON en data/ con fallback transparente a los valores hardcodeados originales si el archivo no existe o está corrupto. 6 archivos JSON creados desde los datos originales.

  • Permiso edit_content_texts: nueva migración SQL. Asignado al grupo 1 (Rei do Mambo).


Cambiado


  • TooltipData: 4 constantes (BALANCE_ASTRAL, HEMISFERIOS_CUADRANTES, TABLA_BALANCE, TABLA_HEMISFERIOS) → 4 métodos estáticos (balanceAstral(), hemisferiosCuadrantes(), tablaBalance(), tablaHemisferios()).

  • InfoAstrologica::obtenerFasesLluna() y obtenerInfoQuiron(): leen de JSON con fallback.

  • SintesisBalance::get(): carga desde JSON vía JsonDataLoader.

  • InformeAstrologico y partes/informe_carta.php: actualizados los 23 call sites de ::CONST a ::metodo().


v3.0.1 — 2026-07-27



Añadido


  • Aspectos en texto de carta compuesta: nueva sección === ASPECTOS === con todos los aspectos entre planetas de la compuesta, indicando orbe, tipo (A=plicativo/S=eparativo) y nombre traducido (Conjunción, Oposición, Trígono, etc.).

  • Balance astrológico en texto de carta compuesta: nuevas secciones === DISTRIBUCIÓN POR ELEMENTOS ===, === DISTRIBUCIÓN POR MODALIDADES ===, === POLARIDADES === con conteos, porcentajes y dominante de cada categoría. Usa BalanceAstrologico y getDominante().

  • Roadmap: añadidas dos nuevas entradas — "Sinastría profunda entre dos cartas" (house overlay, aspectos interpersonales, bi-wheel, enfoque psicológico) y "Tránsitos y progresiones sobre la carta compuesta" (fases del vínculo, progresiones compuestas, interpretación no predictiva).


Corregido


  • Carta compuesta invisible: partes/composite.php envolvía su contenido en un segundo <div class="chart-pane">, lo que causaba que el contenido quedara oculto aunque el panel externo se activara. Eliminado el wrapper duplicado.

  • JS con PHP inline: js/composite.js usaba <?= $carta['id'] ?? 0 ?> que no se procesaba al ser archivo .js. Cambiado a document.getElementById('tab-composite')?.dataset.cartaId.

  • Python: ord('P') → b'P': pyswisseph 2.10.x requiere byte string para se.houses(), no int.


v3.0.0 — 2026-07-27



Añadido


  • Carta Compuesta (Composite Chart): nueva pestaña "🔗 Compuesta" en el sidebar. Muestra listado alfabético de las otras cartas del usuario (excluyendo la actual). Al hacer clic, calcula el midpoint circular entre ambas cartas natales con Swiss Ephemeris. Sub-pestañas: 🪠Carta (SVG), 📊 Informe (Balance + hemisferios + ángulos), 📋 Texto (resumen copiable). Permiso access_composite_chart. Cache en sesión. Nuevos archivos: scripts/calculadora_composite.py, ajax/composite.php, partes/composite.php, js/composite.js, css/composite.css. Documentación: documentation/composite_chart.md.


Corregido


  • Grados en informe RS con formato Signo GG°MM'

  • RS multi-ubicación: 4 llamadas Python, timeout 180s, $auth en scope

  • Resumen texto con pestañas natal/residencia


v2.9.0 — 2026-07-27



Añadido


  • Revolución Solar multi-ubicación: hasta 3 pestañas (🌟 Natal / 📠Residencia / 🌠Elegida) con cálculo independiente para cada ubicación. Las pestañas son sticky y persisten el sub-tab activo al cambiar de ubicación. Placeholder del campo de ciudad: "Escriu la ciutat (deixar buit = residència ó natal)", con auto-precarga de residencia si existe.

  • Texto RS: nueva pestaña 📋 Texto con resumen completo en texto plano de toda la información RS (balance, posicionamiento, superposición, contactes, regentes). Incluye el tipo de ubicación en el título (Natal), (Residencia) o (Elegida).

  • Búsqueda de ciudad al editar: solucionado el bug donde lugar contenía "Rome, Lazio, Italia" y fallaba. Columnas ciudad y ciudad_residencia guardan solo el nombre. Fallback por coordenadas en API. Badge ✅ Coordenadas cargadas.

  • Cúspides casa residencia en resumen texto: si existe residencia, muestra segundo bloque de cúspides.


Corregido


  • Grados en informe RS: todos los valores de longitud ahora se muestran con formato Signo GG°MM' en lugar de grados absolutos decimales (176.83°).

  • Dashboard: widget de residencia con (new AuthManager())->hasPermission().

  • Transitos: $user['id'] → $userId en línea 243.

  • Venv: instalado scipy (faltaba para tránsitos).

  • Favicon: añadido favicon.svg (círculo verde con M).


v2.8.0 — 2026-07-26



Añadido


  • Relocalización de carta natal: funcionalidad completa. Al editar/crear carta, si el usuario tiene el permiso relocation_access, se muestra la sección "🠠Lugar de Residencia" con autocomplete de ciudades. En la vista de carta, pestañas globales "🌟 Carta Natal Nacimiento" / "📠Carta Natal Residencia" que cambian todo el informe de una vez (SVG, hemisferios, ángulos, casas con énfasis). Pestañas sticky al hacer scroll. Widget "ðŸ " en dashboard. Nuevos archivos/métodos: calcularRelocalizada() en CartaNatalCalculator, guardarDatosRelocalizada() en CartaNatalRepository, columnas lugar_residencia, lat_residencia, lon_residencia, timezone_residencia, datos_relocalizada en cartas_natales, migración add_relocation_fields.sql, permiso relocation_access.


Corregido


  • Dashboard: el widget de residencia usa (new AuthManager())->hasPermission() en lugar de $auth que no estaba en scope dentro de renderCartaCard().

  • Transitos: $user['id'] corregido a $userId en ajax/transitos.php:243.

  • Venv: instalado scipy 1.17.1 (faltaba para el cálculo de tránsitos).

  • Resumen carta texto: ahora muestra las cúspides de la carta relocalizada si existe residencia.

  • Revolución Solar multi-ubicación: cuando la carta tiene residencia (y el usuario el permiso relocation_access), la RS se calcula para hasta 3 ubicaciones: Natal, Residencia y Elegida. Pestañas sticky entre el placeholder y los resultados. El placeholder del campo de ciudad ahora dice "Escriu la ciutat (deixar buit = residència ó natal)" y se auto-precarga con la ciudad de residencia si existe. Nuevo método renderResultatsMulti() y renderResultatsIntern() en RevolucioSolarCalculator. JS añade initLocationTabs() + sticky via scroll.


v2.7.0 — 2026-07-26



Añadido


  • Síntesis combinada del Balance Astral: nuevo bloque al final de la sección Balance Astral que combina el elemento, la modalidad y la polaridad dominantes en una frase interpretativa automática. Nuevos archivos: includes/SintesisBalance.php (24 frases), método getDominante() en BalanceAstrologico, método renderSintesis() en InformeAstrologico.

  • Tooltips contextuales por item individual: cada fila del Balance Astral (elementos, modalidades, polaridades) ahora tiene su propio trigger de tooltip. Hover sobre "Fuego" muestra la cabecera "Elementos" + solo Fuego, en lugar de los 4 elementos a la vez. Ãdem para modalidades y polaridades. JS refactorizado con renderItem(), buildContent() acepta itemIndex, handlers leen data-tooltip-item.

  • Subtítulos introductorios en cada bloque del informe con la pregunta guía.

  • Tablas de coherencia bajo Balance Astral y Hemisferios (indicador → pregunta → función).

  • Roadmap en panel admin: nueva sección admin/roadmap.php que renderiza documentation/ROADMAP.md. Accesible desde los cards del panel de administración.

  • Migración para relocalización: nuevas columnas en cartas_natales (lugar_residencia, lat_residencia, lon_residencia, timezone_residencia, datos_relocalizada) y nuevo permiso relocation_access asignado al grupo 1 (Rei do Mambo). Primera fase de la feature de relocalización de carta natal.

  • Documentación ROADMAP.md: lista de funcionalidades futuras con descripciones, acciones y user stories. Primeros ítems: "Síntesis combinada del Balance Astral", "Relocalización de carta natal", "Panel de Textos de Información en Admin", "Revisión del sistema de cobro y suscripción". Cada ítem lleva status (pending/done) con trazabilidad de versión y fecha.

  • Página de Roadmap en admin: nueva interfaz admin/roadmap.php con pestañas Pendientes/Realizados/Todos, índices de navegación, parser Markdown propio (headers, bullets anidados, código inline, blockquotes). Los items se marcan como done editando el comentario <!-- status: ... --> en ROADMAP.md.


Corregido


  • DebugManager: todas las variables de .env relacionadas con debug (NO_DEBUG, DEBUG_ALLOWED_IPS, SAVEQUERIES, DEBUG_SHOW_WARNING, etc.) ahora se definen como constantes PHP. NO_DEBUG=true funciona.

  • Python venv: reconstruido con Python 3.11 (Homebrew) + pyswisseph 2.10.3.2 + timezonefinder 8.2.5. PYTHON_PATH comentado en .env para usar detección automática del venv.

  • Hemisferio Interior/Exterior: corregidas las descripciones invertidas de los hotspots (el tooltip de la mitad superior ahora corresponde al Mundo Exterior —Casas VII-XII— y el de la mitad inferior al Mundo Interior —Casas I-VI—).


v2.6.0 — 2026-07-02



Añadido


  • Menú hamburguesa ☰: Nou menú desplegable a la capçalera de totes les pàgines. Inclou:

- Nom de l'usuari, enllaços a Inici, Admin (si té permisos), Mis pagos, Orbes, Canviar contrasenya i Tancar sessió.
- Botó sense fons (blanc sobre gradient blau), dropdown amb text fosc sobre fons blanc.
- Substituïts els botons individuals del header i del dashboard.
  • Sistema d'orbes personalitzats per usuari: Nova pàgina 🎯 Orbes al menú. Inclou:

- Configuració d'orbes per a carta natal, trànsits i Revolució Solar.
- Emmagatzematge a BD (user_orbs), restabliment per tipus o global.
- Nova classe: includes/UserOrbManager.php.
- Nova pàgina: orbes.php, ajax/save-orbes.php, js/orbes-js.php.
- Nova migració: migrations/add_user_orbs_table.sql.
  • Orbes de trànsits corregits: Nova constant ANGULOS_Y_ORBES_TRANSITOS (3° conjunció/oposició, 2° trígon/quadratura/sextil, 1° menors) enlloc de reutilitzar els 12° natals. Comparació Python dev > orb → dev >= orb.

  • Cerca de ciutat per RS: El formulari de Revolució Solar ara permet cercar la ciutat on es fa la RS (autocomplete via /api/v1/geo/search) en lloc de demanar lat/lon.


Corregido


  • Hamburger menu: Contrast arreglat (text beige --accent-light sobre fons blanc → text #333).

  • Transits orbs: Plutó a 5° Aquari ja no es detecta com a conjunció amb Mart a 17° Aquari (orb 3° en lloc de 12°).


v2.5.0 — 2026-07-02



Añadido


  • Mòdul de Revolució Solar (RS): Nova pestanya amb dibuix de la carta de RS i dades estructurades. Inclou:

- Sub-pestanyes: Carta RS (SVG wheel), Informe (balanç + posicionament + regents), Superposició (cúspides + planetes per casa), Contactes RS-Natal
- Balanç comparatiu 3 cartes (Natal, RS Anterior, RS Actual) per elements, modes i polaritats (només planetes personals + ASC + MC)
- Ubicació configurable: es pot especificar on es fa la RS (lat/lon), per defecte usa la natal
- Càlcul exacte del moment de RS via Swiss Ephemeris (se.solcross())
- Cases carregades (2+ planetes), planetes angulars (≤5°), contactes nodes (≤1°)
- Angles natals projectats a cases RS, dades d'ASC i Sol de RS
- Superposició de cúspides RS → cases natals, planetes RS per casa
- Contactes RS-Natal ordenats per planeta RS (ordre natural) amb orbes: 5° majors, 3° sextil, 1° menors
- Regents de casa
- Nova classe: includes/RevolucioSolarCalculator.php
- Nou script Python: scripts/calculadora_revolucio_solar.py (flags Swiss Ephemeris correctes, timezone robust)
- Nova migració: migrations/add_revolucio_solar_permission.sql
- Noves views: ajax/revolucio_solar.php, partes/revolucio_solar.php, js/revolucio-solar-js.php, css/revolucio-solar.css
- Tests: scripts/test_revolucio_solar.php
  • Sistema d'orbes personalitzats per usuari: Nova pàgina 🎯 Orbes al menú. Inclou:

- Configuració d'orbes per a carta natal, trànsits i Revolució Solar.
- Emmagatzematge a BD (user_orbs), restabliment per tipus o global.
- Nova classe: includes/UserOrbManager.php.
- Nova pàgina: orbes.php, ajax/save-orbes.php, js/orbes.js.
- Nova migració: migrations/add_user_orbs_table.sql.
  • Orbes de trànsits corregits: Ara usen ANGULOS_Y_ORBES_TRANSITOS (3° conjunció/oposició) enlloc dels 12° natals. Comparació Python dev > orb → dev >= orb.

  • Mòdul de detecció d'eclipsis i Sèries de Saros (Bernadette Brady): Integrat al mòdul de lunaciones. Inclou:

- Orbs precisos per eclipsis solars/lunars (total/ambigu/parcial/marginal)
- Identificació de Sèrie de Saros (1-19 North/South, variants Old/New) per any + polaritat del node
- Targeta interpretativa expandible amb aspectes natals en català
- Vista "Calendari d'Eclipsis" filtrable per any (1900-2050)
- Eix de cases oposades als eclipsis
- Dades completes de 40 sèries a data/saros_series.json
- Classes: includes/SarosSeries.php
- Tests: scripts/test_saros.php

v2.4.0 — 2026-05-24



Añadido


  • Pasarela de pago Square: ... (existing content truncated for brevity - already documented)

  • Vinculación usuario-sitio WP: Columna linked_user_id en wordpress_sites. Al vincular un usuario, su suscripción Premium controla automáticamente el flag is_premium del sitio.

  • Aviso de caducidad en plugin WP: El plugin carta-natal-maia muestra un warning âš ï¸ en su panel de configuración cuando la suscripción del usuario vinculado está a 30 días o menos de caducar.

  • Cambio forzado de contraseña: Botón 🔠en cada fila de admin/users.php permite al admin cambiar la contraseña de cualquier usuario (UserRepository::forcePassword()).

  • Cupón interactivo en upgrade: Validación server-side con detalle del beneficio. Precio original tachado + descuento + precio final. Extensión de suscripción visible en el plan. Solo un cupón a la vez (el formulario desaparece al aplicar). Botón "Eliminar" para quitarlo. Arreglado "60€ / mes" → "60€ / año".

  • Migración 019_add_promoter_fields.sql: promoter_id en usuarios y coupons. Campo promotor en admin/users.php y admin/coupons.php.

  • Migración 020_add_linked_user_to_wp_sites.sql: linked_user_id en wordpress_sites. Dropdown en admin/integrations.php.

  • CLI php maia: Herramienta para ejecutar migraciones desde terminal.

  • Mòdul de detecció d'eclipsis i Sèries de Saros (Bernadette Brady): Nou sistema integrat al mòdul de lunaciones. Inclou:

- Orbs precisos per a eclipsis solars i lunars (total/ambigu/parcial/marginal) segons Brady.
- Classificació de l'eclipsi en 4 nivells (total, ambigu, parcial, marginal).
- Identificació de la Sèrie de Saros (1-19 North/South, variants Old/New) per any + polaritat del node.
- Fitxa interpretativa expandible amb data de naixement/fi, aspectes natals i resum curt/llarg.
- Vista "Calendari d'Eclipsis" filtrable per any (1900-2050).
- Dades completes de les 40 sèries actives 1900-2050 (Brady, Appendix 6) a data/saros_series.json.
- Tests unitaris (scripts/test_saros.php).
- Noves classes: includes/SarosSeries.php.
- Fitxers modificats: includes/LunacionesCalculator.php, ajax/lunaciones.php, partes/lunaciones.php, js/lunaciones-js.php, css/lunaciones.css.
  • Mòdul de Revolució Solar (RS): Nova pestanya amb dibuixa de la carta de RS i dades estructurades (formació 2n nivell). Inclou:

- Càlcul exacte del moment de la RS via Swiss Ephemeris (se.solcross()).
- Sub-pestanyes: Carta RS (SVG wheel), Informe (balanç + posicionament + regents), Superposició (cúspides + planetes per casa), Contactes RS-Natal.
- Balanç comparatiu de 3 cartes (Natal, RS Anterior, RS Actual) per elements, modes i polaritats (només planetes personals + ASC + MC).
- Cases carregades (2+ planetes) a la RS, planetes angulars (≤5°), contactes nodes (≤1°).
- Angles natals projectats a cases de RS, dades d'ASC i Sol de RS.
- Superposició de cúspides RS → cases natals, planetes RS per casa.
- Contactes RS-Natal (orbes: 5° majors, 3° sextil, 1° menors), regents de casa.
- Nova classe: includes/RevolucioSolarCalculator.php.
- Nou script Python: scripts/calculadora_revolucio_solar.py.
- Nova migració: migrations/add_revolucio_solar_permission.sql.
- Noves views: ajax/revolucio_solar.php, partes/revolucio_solar.php, js/revolucio-solar-js.php, css/revolucio-solar.css.
- Tests: scripts/test_revolucio_solar.php.

Corregido


  • 502 Bad Gateway en forgot-password: Timeout SMTP reducido de 30s a 10s.

  • ADD COLUMN IF NOT EXISTS: Eliminado de migraciones (sintaxis MariaDB-only, incompatible con MySQL estándar).

  • Tesorería: Cada fila de plan ahora tiene su propio <form> (antes un solo form para toda la tabla causaba pérdida de datos al guardar).


v2.3.1 — 2026-05-24



Corregido


  • Filtro de carta (ajax/main.php): filtrarDatosCartaNatal() compara strtolower($aspecto['acronimo']) contra los acrónimos. id ya no se pierde al no estar en query string.

  • JS filtro (filtro-carta-natal.js): Extrae el id de window.location.pathname con regex /charts/(\d+) si no está en ?id=.

  • Hover de aspectos (svg.js): highlightAspect() ahora busca la línea SVG correspondiente por data-planet1/data-planet2 en vez de comparar por referencia. Al hacer hover en una celda de la tabla de aspectos, la línea SVG se resalta correctamente.

  • Zoom de carta (WheelRenderer.php): openChartFullscreen() ahora crea el modal dinámicamente si no existe en el DOM. Cierre con Escape arreglado.

  • Updater WP: Plugin_Upgrader::upgrade() → descompresión manual. download_url() → wp_remote_get(). Transient 'no_update' → false. (int) get_option() en validate_license().

  • Footer plugin WP: Eliminado <a> anidado dentro del copyright.

  • Versiones plugins: carta-natal-maia v1.4.2, maia-connector v1.0.3.

  • Changelog en updates: check.php + componentVersion() en Functions.php.

  • Arcos WheelRenderer: Sweep ≤180° + sweepFlipped para SVG.

  • Sidebar: switchChartTab(), display: grid, sizing SVG.

  • download.php: maia-connector alias.


v2.3.0 — 2026-05-23



Añadido


  • Sidebar lateral colapsable en vista de carta: Las pestañas horizontales de charts/view.php se reemplazan por un panel lateral izquierdo con toggle ☰. Colapsado: solo iconos (52px). Expandido: icono + texto (220px). Estado persistente en localStorage. En móvil (<768px) vuelve a tabs horizontales.

  • Motor de Cálculo de Tránsitos Adaptativo: Nuevo script scripts/calculadora_transitos.py (~350 líneas) que sustituye las consultas SQL a ephemerides_planetas (~630M filas, ~8 GB) por cálculo dinámico con Swiss Ephemeris + interpolación cúbica (scipy.CubicSpline).

- Grupo rápido (Sol, Luna, Mercurio, Venus, Marte): swe.calc_ut() diario (0.5d para Luna).
- Grupo lento (Júpiter, Saturno, Urano, Neptuno, Plutón, Quirón, Nodos): muestreo cada 15d + CubicSpline con numpy.unwrap para cruce del punto Aries.
- Detección con orbes reales desde ANGULOS_Y_ORBES_ASPECTOS (antes ignorados, solo matching exacto).
- Partil (hora exacta): extrapolación lineal zero-cost desde la derivada del spline.
- Deduplicación: solo el punto de máximo acercamiento por paso consecutivo.
- Rendimiento: 12 meses = 0.037s / 130 llamadas SWE; 3 años = 0.1s / 370 llamadas SWE.
  • Migración 017_drop_ephemerides_planetas.sql: Elimina v_ephemerides_legible y ephemerides_planetas.

  • Soporte True_South_Node: Derivado automáticamente del Nodo Norte (+180°).


Cambiado


  • TransitosCalculator.php: Refactorizado calcularTransitosCompletos() para usar el motor Python vía proc_open() con JSON stdin/stdout. Añadidos ejecutarCalculoTransitos(), adaptarResultadoPython(), lonToRaw() y formatearGradosMinutos(). obtenerRangosTransitos() ahora lee del resultado Python en memoria.

  • ajax/transitos.php: get_date_limits() usa rangos configurables vía .env (TRANSITOS_ANIO_MIN/MAX) en vez de SQL.

  • routes.php: Limpieza de ruta innecesaria.

  • Dependencia Python: Añadido scipy>=1.17 al Python del sistema ServBay 3.11.


Corregido


  • Rangos de tránsitos: Los min/max de cada planeta ahora se calculan desde las posiciones reales de inicio/fin del período, no desde los puntos de aspecto detectados. Corrige falsos rangos de vuelta completa en Saturno y disparidad entre Nodo Norte/Sur.

  • Arcos de tránsito en la rueda (WheelRenderer): El sweep ahora se fuerza a ≤180° (arco corto) con sweepFlipped para invertir el sweep-flag SVG cuando corresponde. Corrige arcos de ~320° (89% del zodíaco) en planetas retrógrados y la posición del label (tSN, tNN).

  • Sidebar lateral: switchTab() renombrado a switchChartTab() para evitar colisión con la función global de script.js que se carga después vía footer.php.


Obsoleto


  • calcularPuntosDeAspectos() y procesarTransitos(): Marcados como @deprecated. Se eliminarán en v2.4.0.


v2.2.5 — 2026-05-22



Corregido


  • Actualización de Plugins WP: Refactorizado run_update() en ambos plugins. Ahora descarga el zip por separado con SSL relajado y download_url(), usa Automatic_Upgrader_Skin + archivo local en vez de WP_Ajax_Upgrader_Skin + URL remota, fuerza FS_METHOD=direct, verifica tanto $result como $skin->result, y comprueba el retorno de activate_plugin(). Esto resuelve el falso "actualizado correctamente" cuando el upgrader fallaba silenciosamente.


v2.2.4 — 2026-05-22



Mejorado


  • Rueda a Pantalla Completa (Desktop): La rueda SVG de la carta natal en el plugin WP ahora ocupa la altura máxima disponible de la ventana en pantallas ≥1024px, permitiendo verla completa sin scroll vertical.


v2.2.3 — 2026-05-22



Corregido


  • Transient Stale en Updater WP: Los plugins carta-natal-maia y maia ahora invalidan el transient de actualización si la versión cacheada ya no es superior a la versión local. Esto evitaba que apareciese una falsa notificación de "actualización disponible" cuando servidor y plugin tenían la misma versión.


v2.2.2 — 2026-05-22



Corregido


  • Fiabilidad de Actualización: Añadida limpieza de caché de plugins de WordPress tras la actualización para asegurar la detección inmediata de la nueva versión.

  • Interfaz de Ajustes: Corregido error de diseño (layout) en WordPress que causaba desplazamientos visuales en el panel.

  • Descarga Pública: Corregido error "Invalid component" en el enlace de descarga de la pantalla de login.


v2.2.1 — 2026-05-22



Añadido


  • Branding Universal: Enlace a la web personal del autor en todos los pies de página (App y Plugins).

  • Acceso Público a Versión: La página de registro de cambios ahora es accesible sin necesidad de autenticación.

  • Promoción de Plugins: Nueva caja de descarga y contacto en la pantalla de login para usuarios de WordPress.


v2.2.0 — 2026-05-22



Añadido


  • Sistema de Logs para Integraciones:

- Nueva tabla wordpress_chart_logs para registrar cada cálculo realizado desde WordPress.
- Registro de datos: Nombre, fecha/hora de nacimiento, lugar, IP, Sistema Operativo y Navegador.
- Seguimiento de Características: El log ahora registra qué secciones se activaron (Planetas, Aspectos, Balance, Luna, Quirón).
- Nueva vista de "Logs" en el panel de administración de integraciones para visualizar estadísticas detalladas.
  • Mejoras en el Plugin WP v2.2.0:

- Actualizada la lógica de envío para incluir las preferencias de visualización en el log del servidor.
- Corregidos errores de permisos en el proceso de auto-actualización.

v2.1.2 — 2026-05-21



Mejorado


  • Sincronización de Versiones: Actualización global de versiones en todos los componentes del sistema (App y Plugins) para asegurar la coherencia del ecosistema Maia.


v2.1.1 — 2026-05-21



Añadido


  • URL de Copyright Premium: Opción para definir una URL personalizada en el copyright de las integraciones premium. Soporte para ocultar el enlace si se deja vacío.


v2.1.0 — 2026-05-21



Añadido


  • Sistema de Licencias Premium:

- Nuevo endpoint api/v1/license/validate para verificar validez de API Key y estado Premium.
- Columna is_premium en tabla wordpress_sites (Migración 014_add_is_premium_to_wp_sites.sql).
- Capacidad de personalización (White-label) para sitios Premium: Título y Copyright personalizados.
  • Plugin WP Carta Natal Maia v1.3.0:

- Validación de Licencia: Comprobación forzada en ajustes y automática cada 24 horas en el sitio.
- Personalización Premium: Campos para Título y Copyright personalizados en el panel de administración.
- Atributos de Shortcode: Parámetros custom_title y custom_copyright soportados (solo para sitios Premium).
- Fase Lunar y Quirón: Nuevas tarjetas informativas con diseño detallado replicando el informe de Maia.
- Configuración Dinámica: Opciones para activar/desactivar secciones (Planetas, Aspectos, Balance, Luna, Quirón) desde ajustes o vía shortcode.
- Versión 1.3.0: Actualización de versión en cabeceras y encolado de scripts/estilos.

Mejorado


  • Motor de Tránsitos (Propuesta Técnica): Diseño de nueva arquitectura para cálculo dinámico "on-the-fly" usando Swiss Ephemeris (Root-Finding) eliminando la dependencia de base de datos precalculada.

  • Robustez de Fase Lunar: Corregidos "gaps" matemáticos en el cálculo de fases de la luna en InfoAstrologica.php.

  • Seguridad en Frontend: Comprobaciones de existencia de nodos DOM en el plugin de WordPress para evitar errores con cachés de servidor.


v1.1.6 — 2026-05-12



Corregido


  • CSRF en admin/users.php: los 5 formularios (change_group, block, unblock, delete, impersonate) no incluían el campo csrf_token desde que se añadió la validación CSRF en v1.0.5. El intento de impersonar, bloquear, desbloquear, eliminar o cambiar grupo devolvía «Token de seguridad inválido». Añadido <input type="hidden" name="csrf_token"> a todos.

  • Migración 013: columnas default_group_id y force_group_sync faltantes en wordpress_sites. El INSERT de WordPressSiteRepository::create() fallaba con SQLSTATE[42S22]: Column not found: 1054 Unknown column 'default_group_id' al crear integraciones WordPress en producción.


v1.1.5 — 2026-05-12



Mejorado


  • Plugin WP Carta Natal Maia v1.1.1:

- Fuente Nunito: reemplaza la pila de fuentes del sistema por Nunito (Google Fonts, pesos 400/500/600/700) cargada vía @import en el CSS.
- Tamaño mínimo 16px: todo el texto del plugin tiene mínimo 16px. Labels pequeñas (footer, orbes, retro) a 14px.
- Tamaños proporcionales: headings escalados (brand 26px, títulos 24px, secciones 18px).
- Símbolos astrológicos a 30px: .astronomicon, .planeta-header, .simbolo-aspecto, .cnm-summary-glyph, .cnm-pt-symbol escalados al mínimo de 30px establecido por convención.
- Responsive: tamaños del breakpoint 480px actualizados proporcionalmente (inputs/botones/tabs a 16px, step-title a 22px).

v1.1.4 — 2026-05-12



Añadido


  • Generador de imagen PNG (ChartImageRenderer): nueva clase GD+TTF que dibuja la carta natal completa como imagen PNG (1200×1200). Incluye rueda con signos, casas, planetas con grados/signo/minutos, líneas de aspecto con símbolos, cabecera con datos personales y tabla de posiciones planetarias. Usa fuente Astronomicon (TTF) directamente — no depende de renderizado SVG del servidor.

  • API v1 chart_image field: POST /api/v1/chart/calculate ahora devuelve data.chart_image con la imagen PNG en formato data URI base64 (además del SVG y HTML de aspectos).

  • Recálculo automático de cartas antiguas: si charts/view.php detecta datos incompletos (planets o casas vacíos), fuerza recálculo vía calcularCartaNatal() y persiste los datos en BD con el nuevo método CartaNatalRepository::guardarDatosCalculados().

  • Método guardarDatosCalculados(int $cartaId, array $datos) en CartaNatalRepository: actualiza solo la columna datos_calculados de una carta existente.


Corregido


  • API v1 renderAspectosList() no mostraba aspectos: la función usaba claves en español con acentos ('conjunción', 'oposición'…) pero AspectosCalculator devuelve las claves en inglés de ANGULOS_Y_ORBES_ASPECTOS ('conjunction', 'opposition'…). Ahora renderAspectosList() recibe directamente el resultado de AspectosCalculator::getAspectosUnicos() y mapea correctamente las claves.

  • Plugin WP v1.1.0: IDs HTML duplicados (#cnm-wheel-container, #cnm-aspects-container) por tabulación sobrante en shortcode.php. Eliminados los divs cnm-tab-* no utilizados. Estructura HTML corregida. Layout de resultados reorganizado: imagen PNG principal + sección de aspectos.


Modificado


  • api/v1/chart/calculate.php: usa AspectosCalculator para generar el listado de aspectos y el contador de stats; genera imagen PNG vía ChartImageRenderer.

  • integrations/wp-plugins/carta-natal-maia/: JS usa data.chart_image (PNG) como vista principal. CSS con clase .cnm-chart-png responsive.

  • charts/view.php: detección de datos incompletos + recálculo + guardado en BD.


v1.1.3 — 2026-05-11



Mejorado


  • Plugin WP Carta Natal Maia v1.0.6:

- Sin filtros ni interactividad: el SVG de la rueda se renderiza sin controles, zoom, ni fullscreen.
- Listado de aspectos en HTML: sustituye el SVG grid por un listado agrupado por tipo de aspecto con nombres de planetas en texto (no requiere fuente Astronomicon).
- Estilos robustos: prefijo #carta-natal-maia-app en todos los selectores + !important en botones para vencer temas WP.
  • REST API v1: POST /api/v1/chart/calculate ahora acepta API keys de ambos tipos (maia y carta-natal-maia).

  • Router: soporte para preflight CORS (OPTIONS) automático en cualquier ruta registrada.


v1.1.2 — 2026-05-11



Añadido


  • GeoNames local — búsqueda de lugares de nacimiento desde base de datos propia, sin depender de la API externa:

- Migración 008_create_geonames_places.sql: tabla geonames_places con FULLTEXT en name + asciiname + alternatenames.
- Script scripts/import_geonames.php: importa allCountries.txt (solo clase P, ciudades/pueblos) en lotes de 1000. Uso: php scripts/import_geonames.php --file=/ruta/allCountries.txt.
- Directorio data/geonames/ para colocar el archivo allCountries.txt.
- Endpoint GET /api/v1/geo/search ahora consulta la BD local (con fallback a API GeoNames si la tabla no existe).
- Migración 009_geonames_indexes.sql: índices B-tree en name, asciiname y population para acelerar búsquedas LIKE + ORDER BY.

Mejorado


  • Output buffering global: ob_start() en index.php para que los endpoints API puedan emitir headers CORS limpios sin interferencia del debug output de init.php.

  • Robustez API geo/search: doble fallback (file_get_contents → curl) para llamadas a GeoNames como último recurso.

  • Respuesta geo/search unificada: ahora devuelve campos compatibles con formato Nominatim (display_name, lon, address.city/state/country) y formato GeoNames (name, lng, countryCode).

  • Búsqueda en formulario de creación Maia: js/script.js usa /api/v1/geo/search (BD local) en vez de Nominatim. Búsqueda automática al escribir 3+ caracteres (con 400ms debounce). Enter para búsqueda manual de 1-2 caracteres.

  • Nombres de región legibles: migración 010_create_admin1_codes.sql + script import_admin1.php traducen códigos FIPS/ISO a nombres (ej: "56" → "Catalonia"). geo/search hace LEFT JOIN automático.

  • Plugin WP Carta Natal Maia v1.0.4: búsqueda automática a 3+ caracteres (antes 2+).


v1.1.1 — 2026-05-11



Mejorado


  • Plugin WP Carta Natal Maia v1.0.2:

- Menú propio «MaiaCN» en sidebar de WordPress (icono â­, posición 30), en lugar de bajo Ajustes.
- Cabecera «Carta Natal by Maia» sobre el formulario.
- Footer «© 2026 Maia by David Herrero» con enlace a la URL de Maia configurada (abre en nueva ventana).
- Formulario unificado: todos los campos visibles a la vez (nombre, fecha, hora, lugar) con labels. El botón de calcular se habilita automáticamente al rellenar nombre, fecha y seleccionar ciudad.
- Estilos CSS para cabecera y footer.

Corregido


  • Panel integraciones: fallback ?? 'maia' para plugin_type en sitios existentes sin la migración aplicada.


v1.1.0 — 2026-05-11



Añadido


  • Plugin WordPress «Carta Natal Maia» (/integrations/wp-plugins/carta-natal-maia/):

- Shortcode [carta_natal_maia] que muestra un formulario paso a paso (nombre → fecha → hora → lugar) y calcula la carta natal de forma anónima.
- Configuración desde Ajustes → Carta Natal Maia (URL de Maia + API Key).
- Búsqueda de ciudad vía GeoNames con autocompletado.
- Resultados: SVG de la rueda zodiacal + SVG de la tabla de aspectos, con tabs para alternar.
- Plug & play: solo requiere API Key generada desde el panel de integraciones de Maia.
  • REST API v1 (POST /api/v1/chart/calculate):

- Autenticación vía header X-API-Key (clave secreta del sitio).
- Rate limiting: 60 peticiones/minuto por API key.
- Validación de fechas (1800–2400) y coordenadas.
- Sin guardar en BD: cálculo puramente anónimo.
- Devuelve JSON con SVG de la rueda zodiacal + SVG de la tabla de aspectos.
- Contador de cartas calculadas por sitio (chart_count en wordpress_sites).
  • Panel de integraciones mejorado (admin/integrations.php):

- Selector de tipo de plugin al crear sitio: «Maia (acceso total · SSO)» o «Carta Natal Maia (solo cálculo anónimo)».
- Badges visuales en listado para distinguir tipo de integración.
- Contador de cartas calculadas visible para sitios de tipo «Carta Natal Maia».
- Validación CSRF en todos los formularios (crear, editar, toggle, eliminar).
  • Migración 007_add_plugin_type.sql: columna plugin_type y chart_count en tabla wordpress_sites.

  • WordPressSiteRepository: nuevos métodos validateApiKey(), incrementChartCount(), getByType().


Cambiado


  • Renombrado: /integrations/wordpress/ → /integrations/wp-plugins/maia/.


v1.0.5 — 2026-05-11



Seguridad — corregido


  • IDOR en AJAX: obtenerPorId() ahora requiere userId en transitos, direcciones, lunaciones y progressions. Las cartas ajenas ya no son accesibles mediante enumeración de IDs.

  • CSRF en POST: añadida validación de token CSRF en /charts/save, /charts/delete, /admin/users. Formularios de creación/edición incluyen campo oculto csrf_token. El JS de eliminación envía el token desde el <meta>.

  • .env inaccesible vía web: añadido <FilesMatch "\.env$"> Require all denied </FilesMatch> en .htaccess.

  • Logs protegidos en Apache 2.4+: logs/.htaccess actualizado a sintaxis Require all denied (la sintaxis Apache 2.2 anterior era ignorada en servidores modernos).

  • Tokens de recuperación hasheados: reset_token ahora se almacena como hash('sha256', $token) en BD, no en texto plano. findByResetToken() compara hashes.

  • Token sin exponer en retorno: requestPasswordReset() ya no incluye el token en el array de retorno.

  • Sin paths ni trazas en errores AJAX: DebugManager::returnAjaxError() ya no incluye file, line ni trace en respuestas JSON (solo success + error).

  • API con autenticación: /api/ ahora requiere partes/RequireLogin.php.

  • XSS almacenado mitigado: los campos nombre, lugar, relacion, notas de carta se escapan con htmlspecialchars() antes de codificarse a JSON para showCartaInfo() en el dashboard.

  • Fuga de emails en compartir: obtenerUsuariosCompartidos() y obtenerUsuariosDisponibles() ya no devuelven email. share-manager.js actualizado para no mostrar emails.

  • TOCTOU en cuota de cartas: verificarLimiteCartas() usa SELECT ... FOR UPDATE para evitar race condition en creación concurrente de cartas.

  • Cookie de sesión condicional: SameSite y Secure ahora dependen de si la conexión es HTTPS. En HTTP local usa Lax + Secure=0, evitando que falle la autenticación en desarrollo.


Corregido


  • Bug regresión en IDOR fix: las funciones calculateDirecciones(), calculateLunaciones() y calculateProgressions() usaban $user['id'] fuera de scope (la variable no es accesible desde funciones standalone). Ahora reciben int $userId como parámetro explícito desde el switch del scope global.


v1.0.4 — 2026-05-11



Mejorado


  • Formulario paso a paso (wizard) en creación de carta natal (js/script.js + charts/create.php + css/styles.css):

- Al iniciar solo se ve "Nombre completo"
- Al rellenar el nombre, aparece "Fecha y Hora de Nacimiento" con transición suave
- Al rellenar fecha (1800–2400) y hora, aparece "Lugar de Nacimiento" con el buscador activo
- Transiciones CSS con .form-step / .form-step-hidden / .form-step-visible
- Modo edición: todas las secciones visibles desde el inicio
  • Info de ciudad seleccionada ahora aparece dentro del mismo contenedor de resultados, con botón "Cambiar ciudad"

  • Auto-selección: si la búsqueda devuelve un solo resultado, se selecciona automáticamente

  • Ajuste de zona horaria (#timeAdjustment) movido a la sección de lugar, bajo los resultados


Corregido


  • Validación de fecha sin rango: validarFecha() en CartaNatalRepository.php ahora exige 1800–2400

  • Resultados duplicados en búsqueda de ciudad: deduplicación por nombre + región + país (js/script.js)

  • Input date con min="1800-01-01" y max="2400-12-31" en charts/create.php


v1.0.3 — 2026-05-10



Corregido


  • Registro de usuario roto (includes/AuthManager.php:376): phone_country y form_load_time se pasaban a UserRepository::create() y se intentaban insertar en usuarios (columna inexistente → SQLSTATE[42S22]). Añadidos al unset().

  • Links hardcodeados en forgot-password (auth/forgot-password.php:118-120): /UserLogin.php → route('/login'), /UserRegister.php → route('/register').

  • Terminología: "carta astral" / "cartas astrales" → "carta natal" / "cartas natales" en todo el código (PHP, CSS, traducciones .po/.mo). Término astrológico correcto.

  • Versión hardcodeada en admin/version.php: ahora se lee dinámicamente del CHANGELOG.md


Añadido


  • Footer general con copyright + versión en 8 páginas (login, register, forgot-password, dashboard, groups, group_edit, version, view)

  • CSS (css/login.css): clase .app-footer + regla .user-login-container > .app-footer para grid de login

  • Función appVersion() en includes/Functions.php: lee la versión del CHANGELOG.md (cache estática)

  • Función copyrightFooter() en includes/Functions.php: combina APP_COPYRIGHT de .env con appVersion() + versión enlaza a /admin/version

  • Variable APP_COPYRIGHT en .env y .env.example para editar el copyright centralizadamente


v1.0.2 — 2026-05-09



Corregido


  • Eliminados todos los estilos inline (style="") de dashboard.php — extraídos a css/dashboard.css

  • Movido el <style> inline de admin/version.php a css/version.css

  • Estilos de botones de destacado movidos de css/direcciones.css a css/dashboard.css

  • Asegurado font-size mínimo de 16px en todas las nuevas clases CSS

  • Tamaño mínimo de símbolos astrológicos 30px en progresiones y direcciones


Mejoras


  • AGENTS.md documentado con reglas de estilo: sin inline CSS/JS, min 16px texto, min 30px símbolos

  • Botones de acción en cards ahora uniformes (36x36px, solo icono)

  • Orden de botones: Ver → Destacar → Info → Editar → Compartir → Eliminar

  • Nombre de la carta clickable (misma acción que botón Ver)


Archivos creados


  • css/dashboard.css — estilos del dashboard

  • css/version.css — estilos de la página de versión


---

v1.0.1 — 2026-05-09



Corregido


  • Call to undefined method Database::prepare() en dashboard.php y ajax/feature_chart.php

— sustituido por $db->query() y $db->fetchOne() (métodos del singleton Database)
  • SyntaxError: redeclaration of let Modal por carga duplicada de Modal.js

— eliminada la carga redundante en dashboard.php (footer.php ya incluye modal.js)
  • filtro-carta-natal.js mostraba error en páginas sin botón "Aplicar Filtros"

— cambiado Utils.error → Utils.log para que solo sea informativo
  • Tabla chart_featured no existente al primer uso

— añadido CREATE TABLE IF NOT EXISTS automático en dashboard.php y ajax/feature_chart.php
  • Estrella de destacado sin feedback visual al hacer clic

— añadido alert() en caso de error + deshabilitado temporal del botón durante la petición
  • Posición de la estrella de destacado movida junto a la etiqueta "Propia"/"Compartida"


---

v1.0.0 — 2026-05-09



Añadido


  • Módulo de Direcciones de Arco Solar: nueva pestaña "Direccions" en la vista de carta

- Calculadora de direcciones de arco solar (1 año de vida = 1 día de tránsito)
- Tabla de resultados con columnas: Pd, Casa, Asp, Pn, Data, Pos(Pd)
- Soporte para aspectes a planetas natales, nodos, Quirón
- Ingressos de casa (conjunción) → "Casa [nº]"
- Ingressos de signo (conjunción) → símbolo del signo
- Indicador de "funció inferior" cuando el planeta supera los 29° de un signo
- Filtros: fecha inicial, duración en años, orbe, planetas dirigidos, planetas natales, aspectos, casas, signos
- Aspectos por defecto: conjunción y oposición
- Permiso access_direcciones ("Ver Direcciones") añadido al sistema de permisos
  • Cartas destacadas: los usuarios pueden marcar/desmarcar cartas como favoritas

- Icono de estrella (★) junto al nombre de cada carta en el dashboard
- Estrella amarilla rellena cuando está destacada, transparente cuando no
- Las cartas destacadas se ordenan primero alfabéticamente
- El estado de destacado es por usuario (independiente del propietario)
  • Página de Versión y Log en el panel de administración (/admin/version)

- Muestra la versión actual y el changelog completo

Archivos creados


  • includes/DireccionesCalculator.php — clase calculadora de direcciones de arco solar

  • partes/direcciones.php — template de la página de direcciones

  • ajax/direcciones.php — endpoint AJAX para cálculo de direcciones

  • js/direcciones-js.php — JavaScript del módulo de direcciones

  • css/direcciones.css — estilos del módulo de direcciones

  • ajax/feature_chart.php — endpoint AJAX para toggle de destacado

  • migrations/add_direcciones_permission.sql — migración del permiso de direcciones

  • migrations/add_chart_featured.sql — migración de la tabla de destacados

  • admin/version.php — página de versión y changelog

  • CHANGELOG.md — este archivo


Modificaciones


  • charts/view.php — añadida pestaña "Direccions" con verificación de permiso

  • partes/header.php — añadido <link> para direcciones.css

  • partes/footer.php — añadido <script> para direcciones-js.php

  • dashboard.php — añadido icono de estrella para destacar cartas, ordenación por destacadas primero

  • admin/index.php — añadida tarjeta "Versión y Log" en el panel de administración

  • routes.php — añadida ruta /admin/version