Parametros, templates e i18n

Esta guia describe el bloque transversal vigente de v3.0 para parametros globales, templates de email, personalizacion visual e internacionalizacion. El contenido fue contrastado contra las rutas administrativas /admin/parameters, /admin/templates y /admin/customization, los EJB que resuelven parametros y mails, las pantallas Wicket que cambian idioma y los scripts de referencia que siembran configuracion inicial.

Ubicacion en el sistema

  • Parametros globales: se administran desde /admin/parameters y afectan a toda la instancia, no a una eleccion puntual.
  • Templates base: se administran con id=0 en /admin/templates.
  • Templates por eleccion: se administran con id=<electionId> en /admin/templates y solo para elecciones no cerradas.
  • Personalizacion visual: se administra desde /admin/customization.
  • Idioma de la UI: se cambia desde la topbar administrativa y desde la topbar publica/tokenizada en ES, EN y PT.

Parametros globales

  • La pantalla de parametros es una grilla plana clave/valor. No hay categorias, tipado fuerte, validadores por familia ni secretos enmascarados desde la UI.
  • Al crear un parametro la clave y el valor son obligatorios. Si la clave ya existe, el alta falla.
  • La edicion solo permite cambiar el valor: la clave queda bloqueada en EditParameterDashboard.
  • La eliminacion existe, pero solo para usuarios con rol ELECTIONS_DELETER.
  • Agregar, editar o eliminar limpia la cache de parametros y deja actividad administrativa persistida.
  • Cuando el backend pide un parametro inexistente, ElectionsParametersEJBBean.getParameter() devuelve cadena vacia, no null.
  • APP tiene una regla especial: si falta, isProd() considera la instancia como productiva; solo devuelve false si el valor existe y no es PROD.

Familias de parametros vigentes

  • Runtime y links base: APP, URL, WEBSITE_DEFAULT y DEFAULT_PHOTO.
  • Correo: EMAIL_HOST, EMAIL_USER, EMAIL_PASSWORD, DEFAULT_SENDER, DEFAULT_RECIPIENT y DEFAULT_SUPPORT_RECIPIENT.
  • Servicios y autenticacion: WS_AUTH_METHOD, WS_LACNIC_AUTH_URL, WS_AUTH_TOKEN, WS_AUTHORIZED_IPS y WS_MAX_PAGE_SIZE. El nombre del parametro de autenticacion centralizada se conserva por compatibilidad con bases existentes.
  • Acceso publico y captcha: PUBLIC_NOMINATION_ENABLED, DataSiteKeyReCaptcha, LOGIN_CAPTCHA_ENABLED, PUBLIC_FAILED_ACCESS_MAX_ATTEMPTS, PUBLIC_FAILED_ACCESS_RATE_LIMIT_CACHE_RESET_HOURS, LOGIN_CAPTCHA_MAX_ATTEMPTS y LOGIN_CAPTCHA_RATE_LIMIT_CACHE_RESET_HOURS.
  • Texto funcional y UX: ACCEPT_NOMINATION_CONDITIONS_ES/EN/PT y ABSTENTION_DEFAULT_TEXT.
  • Sincronizacion external sync: MILACNIC_SYNC_*, incluyendo endpoint, token y umbrales de seguridad para miembros/deudores/Brasil. El prefijo se mantiene por compatibilidad con la configuracion historica.
  • Campus: CAMPUS_URL, CAMPUS_TOKEN y parametros de ventanas/rate limit para chequeos de curso y evaluacion.
  • IA: OPENAI_URL, OPENAI_API_KEY, OPENAI_MODEL, AI_TEXT_PROMPT_TRANSLATION y limites diarios/de ventana para mejora de texto.
  • El script de referencia release-files/ref/parameter_NEW.sql siembra varias de estas claves, pero el codigo tambien consume constantes adicionales que pueden requerir carga explicita segun el entorno.

Personalizacion visual y home publico

  • La personalizacion opera sobre un unico registro global Customization: no existe una personalizacion distinta por eleccion ni por idioma.
  • Se pueden cargar tres imagenes: logo pequeno, logo grande y simbolo. Si no hay binario cargado, la UI usa la imagen de respaldo definida en image/.
  • Las imagenes se validan con la misma regla usada para fotos: solo jpg/jpeg/png, maximo 512 KB y resolucion maxima 400x400.
  • siteTitle y loginTitle son campos globales simples. Si se guardan vacios, la pantalla repone el valor por defecto del recurso advCustomizationDefaultSiteTitle.
  • showHome alterna entre el home publico por defecto y un home HTML custom.
  • homeHtml se edita con Summernote y luego se renderiza con setEscapeModelStrings(false), o sea, como HTML confiado almacenado en base.
  • Cuando showHome=false, el home publico vuelve al contenido por defecto y deja visible el link historico al reporte de auditoria configurado para la version auditada 2.3.

Templates base y templates por eleccion

  • El sistema separa templates base de templates por eleccion.
  • Los templates base viven sin asociacion a eleccion y se crean solo desde /admin/templates?id=0.
  • Al crear una eleccion, createElectionEmailTemplates() copia a esa eleccion todas las plantillas base faltantes.
  • Los templates por eleccion pisan a los base cuando el motor resuelve un envio. Si la eleccion no tiene template de un tipo dado, el backend cae al base.
  • La pantalla de templates por eleccion se bloquea para elecciones cerradas: si se entra por link directo, redirige a ErrorElectionClosed.
  • Crear un template base exige templateType unico. El backend normaliza el tipo a mayusculas antes de persistirlo.
  • Editar una plantilla no permite cambiar el tipo; solo asunto y cuerpo en los tres idiomas.
  • La UI exige siempre asunto y cuerpo en SP, EN y PT, con maximos de 1000 caracteres para asunto y 2000 para cuerpo.
  • La lista ordena NEW primero y luego el resto por templateType.

Propagacion y envio

  • Actualizar un template base no reescribe automaticamente las copias ya existentes en elecciones abiertas.
  • Para empujar un cambio base a elecciones en curso existe la accion Forzar template, disponible solo en templates base y fuera de NEW.
  • forceBaseTemplateToOpenElections() recorre solo elecciones no cerradas, elimina la copia previa del tipo y persiste una nueva copia desde el base actual.
  • El boton Enviar solo aparece en templates de eleccion y unicamente para tipos cuyo metadata permite envio manual; los tipos automaticos quedan sin ese boton.
  • La grilla administrativa permite filtrar por destinatario, alcance estatutario/no estatutario, modo de idioma, modo de envio y texto del tipo.

Resolucion efectiva del mail

  • El motor de mails siempre intenta resolver primero el template de la eleccion y luego el base del mismo templateType.
  • Para EN y PT existe fallback por campo hacia SP: si el asunto o cuerpo en ingles/portugues viene vacio, se usa el valor en espanol.
  • Ese fallback existe en runtime, pero la UI actual igual obliga a completar los tres idiomas al crear o editar una plantilla.
  • El remitente efectivo sale de election.defaultSender y, si falta, de DEFAULT_SENDER.
  • El destinatario administrativo por defecto sale de election.defaultRecipient; si falta, usa DEFAULT_RECIPIENT; si tampoco existe, cae al remitente de la eleccion o al remitente global.
  • Si un template contiene $signature o ${signature}, el motor inyecta el cuerpo del template SIGNATURE resuelto para esa eleccion/idioma.
  • Algunos tipos disparan ademas STANDARD_DISPATCH_NOTICE hacia el destinatario administrativo estandar.
  • Si falta el template LINK_RECOVERY, el backend genera un fallback interno trilingue para no dejar el recovery sin correo.

I18n de la UI y del contenido

  • La UI fija del sistema se resuelve con recursos Wicket desde ElectionsManagerApp.properties.xml, ElectionsManagerApp_en.properties.xml y ElectionsManagerApp_pt.properties.xml.
  • La sesion administrativa y la sesion publica/tokenizada arrancan con espanol como fallback si no hay locale previa valida.
  • En admin, la topbar cambia idioma en caliente y oculta la opcion del idioma actualmente activo.
  • En paginas tokenizadas, el selector de idioma actualiza la sesion y vuelve a cargar la pagina preservando el parametro locale.
  • Los campos dinamicos de eleccion (titulo, descripcion, URL), mails y otros textos de negocio no salen de bundles: se guardan por idioma en base o en parametros.
  • En el modelo Election no existe fallback runtime de titulo/descripcion/link hacia espanol. Si se pide EN o PT, devuelve ese campo.
  • Para compensar eso, cuando una eleccion se guarda con onlySp=true, las pantallas de alta y detalle copian automaticamente los textos y URLs de SP hacia EN y PT.
  • LanguageCode acepta alias como es, sp, en y pt, ademas de variantes como espanol o portugues.
  • La guia interna de .github/copilot-instructions.md refuerza la regla tecnica vigente: para texto visible fijo se debe usar wicket:message y no hardcodear cadenas en la UI.

Que no hace hoy este bloque

  • No existe una taxonomia formal de parametros ni validacion por tipo desde la pantalla administrativa.
  • No existe traduccion automatica general de contenido libre del sistema; la IA aparece como integracion parametrizable, no como traduccion universal aplicada a toda la UI.
  • No existe personalizacion por idioma para siteTitle, loginTitle ni homeHtml: esos valores son globales.
  • No existe propagacion automatica de cambios de template base a elecciones ya abiertas sin usar la accion de forzado.

Bloques relacionados

  • Resultados y reportes: el cierre del circuito funcional principal quedo documentado en esta guia.
  • Votacion y links publicos: la apertura de rutas tokenizadas y recovery quedo documentada en esta guia.
  • Seguridad y accesos: la capa de login, roles, CAPTCHA, rate limits, tokens y WS quedo documentada en esta guia.

Fuentes contrastadas

ElectionsManagerApp, ParametersDashboard, AddParameterPanel, ParametersListPanel, EditParameterDashboard, EmailTemplatesDashboard, AddEmailTemplatePanel, EditEmailTemplatePanel, EmailTemplatesListPanel, EmailTemplateFilterCatalog, CustomizationDashboard, CustomizationPanel, PublicHomeDashboard, AdminTopBarPanel, PublicTokenTopHeaderPanel, PublicTokenBasePage, ElectionsWebAdminSession, SecurityUtils, ElectionsManagerEJBBean, ElectionsParametersEJBBean, MailsSendingEJBBean, Election, ElectionEmailTemplate, LanguageCode, Constants, release-files/ref/parameter_NEW.sql, .github/copilot-instructions.md y los bundles ElectionsManagerApp*.properties.xml.