Antes: <link href="/ns-themes/.../nightspire-style.css?v=2"> en el <head>. Una
peticion aparte, sin minificar y con cache invalidada a mano con ?v=2.
Ahora: app/theme.css, importado al FINAL de globals.css. Next lo compila,
minifica y le pone hash de contenido; se sirve con cache immutable y hay una
hoja de estilo menos (4 -> 3).
⚠ El @import va el ULTIMO y no es cosmético: el tema se diseñó contra los
defaults del navegador y el preflight de Tailwind los pisa (box-sizing,
alturas). Antes ganaba la cascada por cargarse el último en el <head>; ahora
gana por ser el último import. Si sube de sitio, el diseño se rompe.
Las url() pasan a ABSOLUTAS (/ns-themes/ns-ryu/...). Los assets siguen en
public/, y así el compilador no intenta resolverlos: el @font-face declara
.eot/.otf/.ttf que NO existen (solo hay .woff) y con rutas relativas el build
fallaría.
Verificado: los 6 páginas dan exactamente el mismo alto que antes (8159, 1356,
2645, 1356, 2221, 2349 px) con la misma fuente y colores, y el input del login
sigue en box-sizing:content-box — que es justo donde el preflight rompía. Ojo:
el md5 de las capturas NO sirve para comparar, porque la cabecera lleva un vídeo
y cada captura pilla un fotograma distinto.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
De los 11 css/js del tema solo se usa uno: ns-css/nightspire-style.css, que
carga layout.tsx. Los 10 .js no los pide nadie. Medido en un navegador sobre 10
rutas de producción, no deducido con grep: la web no solicita ni un solo JS del
tema.
Son los manejadores jQuery del portal Django, que se borró hoy; los sustituyeron
los componentes React.
Dos detalles que el grep no habría resuelto:
- ns-scripts.js parecía referenciado desde SiteHeader.tsx, pero la coincidencia
era un COMENTARIO que documenta de dónde salió el toggle móvil, no una carga.
Se ajusta el comentario, que si no citaría un fichero inexistente.
- power.js era la copia que UltimoWoW tenía de los tooltips de Wowhead, con
g_host = 'https://wotlk.novawow.com' (dominio muerto) escrito dentro. La web
usa el oficial de zamimg, que carga layout.tsx.
Verificado tras borrar: build limpio, 7 rutas sin errores 4xx ni de JS, el tema
se sigue aplicando y el menú móvil (lo que replicaba nwNavBar) despliega bien.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Renombrado completo de los prefijos heredados: 19 carpetas, 11 ficheros y 318
referencias en 35 ficheros de código, más las clases y las rutas url() de dentro
del CSS del tema. Se usa git mv para conservar el historial.
También fuera del código, que un sed no ve:
- BD: votesite.image_url (4 filas) apuntaba a /nw-themes/...
- Ficheros con la marca vieja en el NOMBRE: novawow-maintenance.webp ->
nightspire-maintenance.webp (lo usa la página de mantenimiento) y
store_novawow_response.js.
⚠ Alias en Caddy /nw-themes/* -> /ns-themes/*: los correos ENVIADOS antes del
rebranding llevan esas rutas escritas y están en las bandejas de los usuarios.
Sin el alias, sus imágenes se romperían. Verificado que las rutas viejas siguen
sirviendo 200.
Nota: ns-js/ y ns-js-handlers/ son CÓDIGO MUERTO (manejadores jQuery del portal
Django, que ya se borró). Se midió en el navegador: la web no pide ni un solo JS
del tema. Se renombran igualmente por consistencia, pero son candidatos a
borrarse.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Marca, dominios y correos: UltimoWoW/Nova WoW -> NightSpire, cualquier URL de
esos dominios -> https://www.nightspire.gg y los correos -> consultas@nightspire.gg.
98 sustituciones en 16 ficheros de textos de usuario (messages/, app/, components/).
Assets: logo largo de cabecera y vídeo sustituidos por los de NightSpire (el logo
nuevo es 214x28, igual que el viejo, así que no hace falta tocar el CSS).
Redes: apuntan a las cuentas de NightSpire, tanto en el pie de la web como en el
de los correos (que seguían enlazando a las de NovaWoW desde el porte del diseño).
Cookie de sesión novawow_session -> nightspire_session. Cierra la sesión de todos
los conectados una vez; se asume ahora, recién hecho el cutover.
Ficheros del tema renombrados: novawow-style.css -> nightspire-style.css y
novawow-main-logo-transparent.webp -> nightspire-main-logo-transparent.webp, para
que la marca vieja no quede ni en las rutas.
El foro externo (foro.ultimowow.com) pasa a ser el nuestro: <Link> a /forum, que
respeta el idioma y no abre pestaña nueva.
NO se tocan y es a propósito:
- Los comentarios que nombran AzerothCore: describen el comportamiento REAL del
core (límite de 12 ítems por correo, convención de baneos, SOAP...). Cambiarlos
a NightSpire los volvería falsos. Además AzerothCore no aparece en la web: las
14 menciones son todas comentarios de código.
- El regex de brandify() sigue buscando los nombres VIEJOS: son los que hay
escritos en las noticias de la BD.
- lib/changelog.ts REPO='Inna/NovaWoW': es la ruta real del repo en Gitea.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Los correos usaban un shell inline distinto en cada remitente. Ahora salen
todos de una sola maqueta, la de security_token, portada de las plantillas de
Django. De las 7 de Django solo security_token y activation traían el diseño;
las otras 5 eran HTML soso.
Las plantillas de Django eran un volcado del DOM de Gmail. Al portarlas se
quitó lo que no era diseño: los enlaces iban envueltos en el rastreador de
Mailjet (079xk.mjt.lu), que además redirigía a ultimowow.com en vez de a
nosotros; había un píxel de apertura, un "Click on me" oculto y atributos que
mete Gmail al mostrar el correo. Las imágenes apuntaban al proxy de Gmail
(ci3.googleusercontent.com), no a nuestro /static/, así que el diseño se
rompía el día que Google dejara de servirlas.
Ninguna URL va a fuego: todas cuelgan de SITE_URL, así que cambiar de dominio
es tocar el .env. En un correo han de ser absolutas (se abre desde Gmail), así
que se construyen a partir de esa variable.
El logo nw-mail-logo.png daba 404: solo existía el .webp del tema, que es el de
UltimoWoW (león negro + letras "UW"). El auténtico de NovaWoW, un león de acero
sin letras, sobrevivía únicamente en la caché de Gmail y se recuperó de ahí
(600x320 RGBA, íntegro).
Verificado renderizando el original y el nuestro en un navegador y comparando:
cuadran pixel a pixel. Eso destapó dos fallos que se corrigen aquí: faltaba la
etiqueta <h1> de apertura, y el estilo de los párrafos de datos era el de la
letra pequeña del pie (11px/17px) en vez del real (14px/21px).
El activation de Django mandaba la contraseña en texto plano; aquí no se manda.
mail.ts: leía EMAIL_USE_SSL pero ignoraba EMAIL_USE_TLS, así que en el puerto
587 el STARTTLS era oportunista y, si el servidor no lo ofrecía, nodemailer
enviaba en claro. Ahora requireTLS lo hace obligatorio.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Dos arreglos pendientes que quedaron señalados:
1. "Sacedorte" era una errata de "Sacerdote" en tres categorías (3-10, 4-10 y
19-9; la 20-9 estaba bien). Se veía así en la web en español. Corregido en la
BD y, sobre todo, en el seed `store_catalog.sql`, que la traía 3 veces: sin
eso, reconstruir la BD la resucitaba. Regenerado store_category_en.sql (217
nombres distintos en vez de 218: las dos grafías ya son una).
Un escaneo por parecido contra los términos oficiales de los DB2 confirma que
era la única errata; el resto de casi-coincidencias son plurales legítimos
("Espadas" vs el "Espada" del juego).
2. El cuadro del ítem medía 160px y el del store original 200. Igualado. Solo
afecta a /store: send-gift fija las columnas de su rejilla a 160px y hace
width:auto, y se ha comprobado que sigue midiendo 160.
Con solo cambiar la anchura se quedaba en 200 en vez de 214: el tema se
diseñó para el content-box del navegador y el preflight de Tailwind mete
border-box, así que el padding y el borde dejaban de sumar (el mismo problema
que ya estaba arreglado para los inputs). Se restaura content-box solo en la
tienda, porque en la rejilla de send-gift desbordaría las columnas.
Medido en el navegador: el cuadro pasa a 214px de ancho, que es lo que mide el
del original (213 en la captura). send-gift sigue en 160.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replica el preview del store original: un icono en el cuadro del ítem que, al
pasar el ratón, muestra el render del objeto. El CSS ya estaba en el tema
(nw-st-tooltip-w / nw-st-img-tooltip / nw-img-display, copiado del original);
solo faltaban el markup y las imágenes.
- Los 545 PNG se sirven desde nw-images/nw-displays/ en vez de enlazar al
servidor original, para no depender de un tercero que puede cortarlo.
- Solo lo llevan los ítems equipables (610 de 3068): el resto no tiene
apariencia, igual que en el original. El dato ya estaba en la columna
`preview` de home_store_item y llegaba hasta el componente sin usarse.
- El icono va con `fas`, no con el `fa` suelto del original: cargamos Font
Awesome 6, donde solo .fas/.fa-solid activan la fuente, y el `fa` de FA4/5
no pintaría nada sin el shim de compatibilidad.
Descartado el visor 3D de wowhead: zamimg sirve el meta del modelo con lista
blanca de orígenes (403 desde nuestro dominio, 200 solo desde wowhead.com), así
que solo funcionaría proxeando sus assets para saltarse esa comprobación.
Verificado en el navegador: oculto por defecto, visible en hover, imagen 200.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Aplana el catálogo y lo pagina (8 por página = 2 filas de 4) con controles
Atrás / 1 2 3 / Siguiente centrados. Nuevas clases .gift-grid (grid 4 cols,
responsive a 2 en móvil) y .gift-pagination en novawow-style.css.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- CharacterSelect: componente reutilizable que colorea las opciones por clase
(class="priest big-font"…) y el <select> con la clase seleccionada. Usado en
unstuck, revive, gold, transfer, trade-points, servicios de pago y recruit.
getGameCharacters ahora devuelve classCss.
- /unstuck (+revive): diseño del original (info + NOTA, prompt, opciones coloreadas,
botón "Desbloqueado"/"Revivido" con refresh).
- /vote-points: seed de los 4 sitios con logos y URLs (sql/seed_votesites.sql);
botón voted-button para sitios en cooldown; etiqueta "Nota:" separada.
- account-info.png (imagen nueva) y CSS de los paneles de cuenta: se añade
background-blend-mode: saturation y background-size en #account-settings y
.account-fieldset para que la imagen salga como el original.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Activación de 2FA (TOTP) para el login del juego, guardando el secreto en
acore_auth.account.totp_secret tal como lo lee el bnetserver 3.4.3.
- lib/two-factor.ts: TOTP (HMAC-SHA1, 30s, 6 dígitos, ±1) idéntico al core
(verificado contra los vectores RFC 6238), Base32, otpauth, y codificado
del secreto: crudo por defecto o AES-128-GCM (ciphertext‖IV12‖tag12) si se
define TOTP_MASTER_SECRET (mismo hex que TOTPMasterSecret del servidor).
- Flujo seguro sin bloqueos: el secreto se genera y queda PENDIENTE en la
sesión; sólo se escribe en la cuenta tras verificar un código válido.
- /api/account/2fa: activar (password + token de seguridad), verificar y
desactivar (con código actual). QR generado en el servidor (el secreto no
sale a terceros).
- Página + componente fieles al markup (preview, pasos, copiar clave, ojos).
Verificado E2E: activar -> QR/secreto -> verificar -> totp_secret = 20 bytes
(igual al secreto escaneado) -> desactivar -> NULL.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Los SVG no tenían tamaño intrínseco y se renderizaban enormes encima del
texto. Se porta el layout flex de .dnt-methods del tema original y se
dimensionan los iconos (22px, en línea con el texto) igual que se veía
PayPal. Los SVG llevan ahora width/height explícitos.
Verificado además el flujo Stripe de extremo a extremo (tarjeta de prueba
4242): pago -> página de éxito -> 100 PD acreditados por €1 con reclamo
atómico idempotente. Datos de prueba restaurados tras la verificación.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Elimina las pestañas de PayPal/dLocal/Crypto/Skrill y por país; deja
Información + Stripe + SumUp (las dos únicas pasarelas que se usarán).
- Stripe: totalmente funcional reutilizando createCheckoutSession + webhook
+ página de éxito. Nueva ruta /api/dpoints/checkout crea la sesión con
importe elegido por el usuario (1 unidad = 100 PD).
- SumUp: integración real (lib/sumup.ts) mediante checkout hospedado,
habilitada al definir SUMUP_API_KEY/SUMUP_MERCHANT_CODE; si no, avisa.
- Nuevo servicio de entrega `dpoints` (lib/paid-services.ts) que acredita
PD en home_api_points; entrega idempotente vía reclamo atómico.
- Página /d-points-success entrega ambos proveedores (session_id/ref).
- Iconos SVG generados para cada pasarela (stripe/sumup, marca + wordmark).
- Moneda configurable con DP_CURRENCY (por defecto EUR).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reproduce fielmente el panel de compra de PD de UltimoWoW como componente
cliente con pestañas (Información, PayPal, dLocal Go, Crypto, Skrill y
métodos alternativos por país: Argentina, Chile, Colombia, Perú).
- Página servidor con login requerido (redirige a /login y /select-account
como battlepay); inyecta username de la cuenta de juego e IP reales.
- Pestañas, tabla de rangos con mostrar/ocultar, y calculadora ARS
(dolarapi) migradas a estado/efectos de React.
- Formularios con casilla de T&C que habilita el botón; PayPal usa
PAYPAL_BUSINESS_EMAIL por entorno; dLocal/NOWPayments muestran aviso
hasta configurar su backend (no se fabrican credenciales/gateways).
- Banderas por país y logo de NOWPayments añadido a nw-logos.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Los fieldsets Datos básicos/Estado de la cuenta ahora replican el markup nuevo:
iconos Font Awesome por campo (account-ficon), .separate account-info,
«Nombre de la cuenta», correos enmascarados (maskEmail), PD | PV en una línea
(dp-color/vp-color), Token, «2FA: Desactivado» (fa-lock-open red-info), Cuenta
baneada con enlace «Consultar historial» (/ban-history), reclutada y amigos.
Se quita Créditos Battlepay. Clases account-ficon/account-info al tema; claves
i18n accountName/twofaLabel/twofaOff/banHistoryLink.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
accountTools en el orden del markup: cambiar contraseña, 2FA (email-icon,
label purple-info), transferir PD, comercio de PD, código promoción, token,
recluta, renombrar hermandad, votar, adquirir PD. «Cambiar correo» (que
tenemos y no está en la lista) al final; panel admin el último (solo admin).
Tool.labelClass para el morado del 2FA. Iconos nuevos del sprite: trade-pd-icon
(-299 -928) y color .purple-info (#b172ff) añadidos al tema. Claves i18n nuevas
(svc2FA/TransferDP/TradePD/Promo/RenameGuild/DPoints). Rutas nuevas → 404 aún.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- characterTools reordenado y completado según el markup del usuario (14 items):
...gold, Rastreador de misiones (/quest), transfer, Recuperar personaje
(/restore-character), Recuperar ítems (/restore-items), Tienda (/store),
Enviar regalo (/send-gift). Se retira battlepay del panel (queda en cabecera).
Claves i18n nuevas (svcQuest/RestoreChar/RestoreItems/StoreItems/SendGift).
- Sprite de iconos actualizado a account-icons.png (de uw-ryu) que incluye el
icono de regalo; CSS: .acc-icon → .png, send-gift-icon (-424 -553) y promo-icon
reubicado (-174 -928), verificado que las 25 posiciones restantes coinciden.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reescritura completa del frontend Next.js del sistema visual Tailwind
"simulado" al tema Django original (nw-ryu), para paridad pixel con la
web actual antes del cutover.
- Tema real: copia de static/nw-themes/nw-ryu + favicons a public/, el
layout carga el novavow-style.css real de ultimo (gana la cascada sobre
Tailwind) + Font Awesome.
- Shell replicando los partials Django: SiteHeader, Video, Social, Footer,
ServerClock; home con estructura real (main-page/middle-content/...).
- Helpers reutilizables: PageShell (main-page > middle-content > body-content
> title-content) y ServiceBox (title-box-content + back-to-account).
- Paginas migradas a clases reales del tema (fieldset/tool-button/char-box/
item-box/info-box-light/max-center-table/alert-message/botones reales),
eliminando el markup Tailwind (.nw-btn/.nw-card/.nw-input):
auth (login/register/recover/reset/select-account/activate),
cuenta + servicios de personaje (revive/unstuck/rename/customize/
change-race/change-faction/level-up/gold/transfer + pago Stripe),
ajustes (change-password/change-email/security-token),
comunidad (vote-points/recruit/battlepay), foro completo, y
admin (indice + 7 secciones + los Admin*Manager).
- Se conserva el bilingue (next-intl); claves nuevas en messages/es|en.json.
Verificado: typecheck + build OK; rutas protegidas 307->login; sin
MISSING_MESSAGE; cero Tailwind residual (solo .nw-tool-btn/.nw-page,
clases propias en globals.css).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- lib/data/zone-names.json: ZONE_NAMES (9156 zonas) exportado de zone_definitions.py.
- lib/character-info.ts: getZoneName, getClassCss/getClassName, getRaceName y
getCharacterImage (raza/clase/género -> /races/big-*.webp, con validación de
compatibilidad clase-raza y fallback unknown), portado de account.py.
- lib/account.ts: Character enriquecido (race, class, zone, imageUrl, class/raceName).
- account page: tarjetas con imagen de raza, color de clase WoW, nivel, raza/clase,
📍 zona y oro. globals.css: colores de clase (.class-*).
- public/races: 20 imágenes de raza del tema + unknown.webp.
Verificado: build OK, imágenes 200, /account 307→login. El JSON de zonas se usa
solo en servidor (no infla el bundle cliente).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Copia los logos del tema original (nw-logo -> public/brand/logo.webp,
nw-long-logo -> logo-long.webp).
- Header: logo + nombre. Home hero: logo largo con glow dorado.
- Footer: logo + copyright + enlaces (inicio/foros/votar/registro), i18n.
Verificado: logos se sirven (200), home 200.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Inicia la reescritura del frontend a una app Next.js con SSR (Django pasará a ser
API JSON). No toca producción: Django sigue sirviendo www; Next corre aparte en :3001.
- web-next/: Next.js 16 App Router, TypeScript, Tailwind CSS v4, alias @/*.
- lib/api.ts: cliente de la API Django (SSR -> 127.0.0.1:8001; navegador -> /api
relativo vía Caddy).
- app/page.tsx: home con SSR por petición (force-dynamic) que hace fetch de
/api/home/news/ y /api/home/status/ y renderiza noticias + estado con Tailwind.
- app/layout.tsx: lang=es + SEO (title/description/keywords/OpenGraph) por el
Metadata API de Next (renderizado en servidor).
- Servicio systemd novawow-next (next start -p 3001, DJANGO_API_BASE).
Nota Next 16 (breaking): params/searchParams son Promise (await); fetch no se
cachea por defecto. Verificado: SSR sirve HTML con datos reales de Django y SEO
en el <head>; producción Django intacta.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>