El nivel/rango usaba el saldo de PD actual, que baja al gastar. Ahora se basa en
el total donado = suma de pagos confirmados (Stripe mode test/live + SumUp),
convertidos a PD (amount * 100). Cuenta todas las pasarelas y donaciones mixtas y
no baja al gastar PD. Se usa max(donatedPD, saldo) para no rebajar el rango a
nadie (p.ej. PD de promo). getAccountDashboard expone donatedPD. Verificado:
cuenta 15 con €43 en pagos -> Nivel 11 aunque el saldo sea 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
15921 'The Den' -> 'La Guarida'; 16406/16407 '[DNT]' (marcador interno de
Blizzard, se conserva). Ahora todos los ids del mapa EN tienen también ES.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fusiona las 516 zonas ausentes del wow_zones.php español de FusionCMS en
lib/data/zone-names.json (solo las que faltaban; se conservan las existentes),
ordenado por id. Ahora todos los ids con nombre EN tienen también ES.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Añade mapa de zonas en inglés (lib/data/zone-names-en.json, 9675 zonas de
FusionCMS wow_zones.php; cobertura 100% de los ids del mapa ES) y nombres de
raza/clase EN (wow_constants.php). getZoneName/getRaceName/getClassName aceptan
locale (EN cae a ES si falta). getAccountDashboard(session, locale) lo propaga y
my-account pasa el idioma. El dinero (oro/plata/cobre) usa iconos, universal.
Verificado: Innadin -> Human/Paladin/Stormwind City en /en.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
formatFecha usaba es-ES fijo; ahora recibe el locale y formatea en en-US para
inglés. /en/changelogs muestra "July 14, 2026 at 07:55 PM"; /es/ en español.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Los formularios de crear categoría/foro aceptan nombre/descripción en inglés, y
se añade EDICIÓN en línea de categorías (name, name_en, order) y foros (name,
name_en, description, description_en). lib/admin-forum: createCategory/createForum
con EN + updateCategory/updateForum; rutas PUT en category/[id] y forum/[id].
Claves Admin nuevas (nombre/descripción EN). Verificado: listado con EN + update
round-trip; PUT protegido (403 sin admin).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
forum_categories.name_en y forums.name_en/description_en (sql/add_forum_en.sql,
aplicado en prod y traducidos los existentes: Comunidad/Anuncios/Discusión general).
getForumIndex(locale) y getForum(id, locale) usan EN si existe, si no caen al
español. Las páginas del foro pasan el locale. Labels (Temas/Mensajes) ya estaban
traducidos. Verificado: /en/forum en inglés, /es/forum en español.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
getSanctions devuelve claves (scopeKey account/battlenet/character + scopeName;
statusKey active/activePermanent/expired) en vez de español. La página traduce
alcance ("Character: {name}") y estado; "Permanente" ya usaba clave. Motivo y
autor son datos del GM (no se traducen). Nuevas claves History.ban.scope/status.
Verificado con sanciones de prueba (todos los combos resuelven en es y en).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
La lib devolvía la acción ("Token de seguridad solicitado") y el estado del login
web ("Conexión exitosa"/"Contraseña incorrecta") en español. Ahora devuelve claves
(actionKey='tokenRequested'; statusKey='success'/'wrongPassword'/'other' + statusRaw)
y la página las traduce (History.security.action/webStatus). El coloreado rojo pasa
a depender de statusKey==='wrongPassword'. Verificado con datos reales.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extrae la lógica de concepto traducible a lib/tx-concept.ts (buildConcept +
purchasedPD + SERVICE_CONCEPT) y la reutilizan points-history y trans-history.
La columna Concepto de trans-history ahora se traduce (reusa History.points.concept.*)
en vez de mostrar el product_name en español. Corrige también la sombra de
variable en PlatformBox (map t -> tx). Verificado con la cuenta 15.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Los valores de las columnas Concepto/Método/Estado venían en español desde la lib.
Ahora getPointsHistory devuelve CLAVES (conceptKey+args, method 'vote'/'promo',
status 'delivered'/'pending'/'credited') y la página las traduce. Concepto por
servicio ("Rename character: {char}", "Vote on {site}", "Code {code}", "{n} PD");
los pagos heredados sin servicio caen a conceptRaw. Claves nuevas en History.points.
Verificado con la cuenta 15: todas las combinaciones resuelven en es y en.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
home_noticia gana columnas titulo_en/contenido_en (sql/add_news_en.sql). getNoticias(locale)
usa la versión EN si existe, si no cae al español (título y contenido independientes); la fecha
también se formatea por idioma. El panel de admin permite escribir la traducción al crear y EDITAR
noticias existentes (nuevo PUT /api/admin/news/[id], updateNews). Claves Admin nuevas (título/
contenido EN, editar/guardar). Probado: /en/ muestra EN, /es/ ES; PUT guardado (403 sin sesión).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Los <title> estáticos estaban en español fijo. Se migran 31 páginas a
generateMetadata reutilizando la clave de título ya traducida de cada página
(o del <h1>). Se traducen además los PageShell title hardcodeados de las 6
páginas CharServiceB y los títulos de download-client y changelogs (+ su
mensaje de error). tsc/build OK, paridad es/en, <title> cambia por idioma.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Se externaliza el texto español hardcodeado de ~55 archivos a next-intl y se añaden
traducciones al inglés, con paridad de claves es/en. Nuevos namespaces: History,
CharService, CharServiceB, Points, Legal, UI, Misc (+ altas en Common/Admin).
- Historiales (PD/PV, transacciones, sanciones, seguridad), servicios de personaje
(transfer, send-gift, quest, restore-*, change-*, customize, level-up, gold, rename),
PD/pagos (d-points, trade, promo, transfer-dp, rename-guild, DPointsTabs), páginas
legales (cookies, privacidad, términos, reembolsos, aviso legal, contacto), layout
(cabecera, footer, cookies, 2FA, descargas, jugadores, recluta) y páginas varias
(home, reino, ayuda, addons, 2falogin).
- Textos con markup inline via t.rich; interpolación con ICU.
- Componente <NoteLegend/> para la leyenda NOTA/NOTE compartida.
- payLabel/confirmText de los servicios de pago traducidos.
- Verificado: tsc OK, next build OK, todas las claves t() resuelven en es y en,
todos los t.rich casan etiquetas, páginas 200 en /es/ y /en/ sin claves crudas.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
El nombre del reino (p.ej. "Trinity") salía en minúsculas y las minúsculas caían
a una fuente de reserva (Futura es de mayúsculas), desentonando con el resto del
nav. Se muestra en mayúsculas como los demás ítems.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
El nav ya mide igual que el original (1112px, items 174px, Futura) tras el fix de
box-sizing; el CSS del tema se servía sin versión y quedaba cacheado. Se añade
?v=2 a novawow-style.css para bustear la caché del navegador.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
trailingSlash true ponía barra en todo (/es/content-creators/). Se pasa a
skipTrailingSlashRedirect + normalización en middleware: raíz de idioma /es → /es/
(con barra), y cualquier sub-ruta con barra final se redirige sin ella
(/es/x/ → /es/x). Sin bucles. Las /api quedan fuera del middleware (sin 308).
El redirect del logout apunta a /es/.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
next.config: trailingSlash true → /es redirige a /es/ y los enlaces se generan
con barra. Se ajustan a barra final los destinos internos que se enlazan a mano
(logout /log-out/ y su redirect, y los window.location.assign de login/
select-account) para evitar el salto 308 extra.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Los enlaces internos del header eran <a> planos sin prefijo (/download-client…);
ahora usan <Link> de next-intl → /es/download-client, /es/changelogs, reino,
jugadores, videos, ayuda y los logos. Externos (WOTLK DB) y el logout (route
handler) siguen como <a>. Resuelve también los avisos no-html-link-for-pages.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
El tema nw-ryu se diseñó para content-box; los items del nav usan min-width:126px
+ padding:24px (ancho total 174px). El preflight de Tailwind fuerza border-box, que
mete el padding dentro del min-width -> items ~48px más estrechos y header apretado
respecto a ultimowow.com. Se revierte a content-box en .nav-bar a / .nav-dropdown-btn
/ .nav-dropdown-content a (mismo patrón que ya se hizo con inputs/tablas/img).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
El selector de cuentas de juego listaba el nombre interno (15#1). Ahora usa
wowAccountLabel (mismo criterio que my-account/cabecera): «15#1» → «WOW1». La
etiqueta se calcula en el Server Component (bnet.ts importa crypto, no vale en
cliente) y se pasa al formulario.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Con router.push el layout persiste entre rutas, así que la cabecera seguía
mostrando "Conectar/Crear cuenta" tras el login hasta recargar. Ahora login y
select-account hacen window.location.assign(/{locale}/...) para que el servidor
re-renderice el layout/cabecera con la sesión nueva.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Construir la URL desde request.url daba https://localhost:3001/es detrás de Caddy
(usa la dirección interna). Ahora el Location es relativo (/es), que el navegador
resuelve contra el dominio público real.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
React 19 bloquea href="javascript:void(0)". SiteHeader: DESCONECTAR ahora enlaza
a /{locale}/log-out (ruta real), el menú hamburguesa y el logo pequeño usan
role/button o href real. PostActions (foro): editar/eliminar pasan a role=button.
Se elimina el logout por fetch del header (lo hace la ruta /log-out).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Route Handler GET en app/[locale]/log-out: destruye la cookie de sesión y
redirige (303) a /{locale}. Enlace directo visitable (/es/log-out, /en/log-out)
sin depender de JS; reutiliza getSession().destroy().
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Antes el idioma por defecto (es) se servía sin prefijo. Ahora todas las URLs
llevan /es o /en; la raíz / redirige a /es y las rutas sin prefijo redirigen al
idioma por defecto con prefijo.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
La columna Usuario mostraba el nombre interno de la cuenta de juego (15#1). Ahora
muestra la etiqueta WOW1 (nº tras #; con varias serían WOW2, WOW3…) y debajo la
cuenta Battle.net (email), sin añadir columnas. Helper wowAccountLabel extraído a
lib/bnet.ts (mismo criterio que my-account).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tres tablas: actividad (solicitudes de token, home_securitytoken), conexiones
al reino (logs_ip_actions + account.last_ip/last_login como conexión actual),
y conexiones web (home_loginattempt, estado Exito/Fracaso -> Conexión exitosa/
Contraseña incorrecta). lib/security-history.ts (getSecurityHistory), tolerante
si falta la tabla. Django era stub.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lee las BD de AzerothCore: baneos de account_banned (cuenta),
battlenet_account_bans (Battle.net) y character_banned (personajes de la
cuenta); muteos de account_muted. Estado Activo/Activo (permanente)/Expirado
según bandate/unbandate/active. Dos tablas (baneos con alcance, muteos) + info.
lib/ban-history.ts (getSanctions), tolerante si AC no está poblado. Django stub.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Dos cajas por pasarela (Stripe mode test/live, SumUp mode sumup) desde
home_stripelog, con logo, nota y tabla ID/Estado/Concepto/Fecha/Cantidad.
Estado PAID (fulfilled=1) / PENDING. Se omiten dLocal, Crypto y PayPal del
diseño original. lib/trans-history.ts (getPaymentTransactions). Django era stub.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Historial unificado por cuenta que combina las fuentes reales: home_stripelog
(pagos Stripe mode test/live + SumUp mode sumup), home_votelog (PV de votos) y
home_promoredemption (PD/PV por código). Detecta compras de PD ("N PD") vs
servicios pagados en €. lib/points-history.ts (getPointsHistory + getPointsBalances)
y página con el diseño (info + tabla Fecha/Concepto/Método/PD/PV/Importe/Estado
+ saldo actual). El Django original solo tenía un stub.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SumUp no permite cobros por debajo de 1 €. Se actualizan las dos pociones
(0.50 -> 1.00) en el seed y en la BD de prod.
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>
Envía ítems de la tienda por correo al personaje de un amigo, pagado por
SumUp. lib/gift.ts (catálogo por categoría, priceCart con precios reales de
BD, sendGiftByMail vía SOAP .send items troceado a 12/correo + anti-inyección);
servicio send-gift en PAID_SERVICES; ruta dedicada /api/gift/checkout (origen
propio, destino existe, token de seguridad, carrito); SendGiftForm + página con
el diseño; i18n Paid[send-gift]; seed_giftitems.sql (4 cat, 8 ítems).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Nuevo servicio de pago `restore-item` (getRestoreItemPrice default 1€, fulfill
SOAP `.item restore <recover_id> <char>`). Al pulsar "Recuperar" se crea un
checkout de SumUp y al pagar se ejecuta el restore.
- Se quita el descuento de 100 PD y el gate "No tienes PD suficientes".
- La búsqueda sigue igual (gratis, cooldown 8h, Turnstile).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- /restore-character: recupera personajes borrados por BD (como .character deleted
restore). Condiciones: nivel>60, borrado <30 días, DK no si ya hay DK activo,
nombre libre, cooldown 12h/personaje. Gratis. Tabla home_restorehistory.
- /restore-items: recupera ítems borrados vía SOAP del core (.item restore list /
.item restore); el core aplica calidad/equipable/BoP/<7días. Cada ítem 100 PD
(reembolso si SOAP falla), consulta con cooldown 8h/personaje + Turnstile.
Tabla home_itemsearchhistory.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Nueva ruta /transfer-character (10€ SumUp); borra /transfer (Stripe) y actualiza
el link del panel.
- lib/transfer-character.ts: precheck con todas las condiciones — personaje offline,
contraseña, token de seguridad, 2FA activo, cuenta destino válida (≠ propia) y,
para Caballeros de la Muerte, la cuenta destino debe tener un personaje nivel >=55
y no tener ya un DK; + bloqueo de 5s tras transferencia reciente.
- El hook precheck de PaidServiceConfig ahora recibe {accountId,email,character,body}.
- TransferForm: contraseña + token (con ojos), provider sumup, confirm.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- /change-race-character (3€), /change-faction-character (5€, valida condiciones:
sin hermandad/correo/subastas/capitán-arena y oro <= cap por nivel),
/level-up-character (10€), /gold-character (oro por correo SOAP). Cada uno borra
su ruta antigua y actualiza el link del panel.
- SumUp: hook precheck en PaidServiceConfig (condiciones cambio de facción);
columna home_stripelog.metadata para campos extra (gold_amount).
- /quest-character: rastreador de estado de misiones/cadenas (clase, Hijos de
Hodir, misión por ID) en personaje offline; cooldowns por categoría, Turnstile,
IDs de misión verificados en wotlkdb 3.3.5a. Tabla home_questsearchhistory.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- /rename-character y /customize-character: renombrar/personalizar pagados por SumUp
(getRenamePrice/getCustomizePrice). SumUp ahora es service-aware: columna
home_stripelog.service; createSumUpCheckout guarda service+character;
fulfillSumUpCheckout despacha a la acción del servicio (.char rename/customi) o,
sin service, acredita PD. [service]/checkout acepta provider:'sumup';
PaidServiceForm acepta provider+confirmText; service-success maneja el return SumUp.
Se eliminan las antiguas /rename y /customize (Stripe).
- /revive-character (comparte ReviveServiceContent); se elimina /revive.
- Renombres de ruta + todos sus enlaces:
/account -> /my-account, /recruit -> /recruit-a-friend, /unstuck -> /unstuck-character.
(/select-account y /api/account/* intactos.)
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>
- /security-token: diseño completo del original (info + advertencia + NOTA 7 días),
fecha en formato HH:MM:SS DD-MM-YYYY, botón "Token enviado", enlace a /recover.
- /recover: 4 opciones (contraseña por usuario, nombre de cuenta, token de seguridad
y enlace de activación por correo); recuperación de token nueva; Turnstile por envío.
- /vote-points: caja de info con las 7 secciones Q&A + panel "Sitios de votación" con
tarjetas inline-div (imagen, PV, último voto), botón refrescar; abre el sitio y acredita
PV al volver. lib/vote.ts + getVoteSitesForAccount.
- /rename-guild: renombra una hermandad de la que la cuenta es Maestro por 1000 PD +
token de seguridad; SOAP .guild rename con comillas; reembolsa los PD si SOAP falla.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- /transfer-d-points: transferir PD a la cuenta dueña de un personaje
(requiere token de seguridad; movimiento atómico con FOR UPDATE).
- /trade-points: comercio PD<->oro mediante códigos de 1 solo uso
(contraseña + token + Turnstile; oro al creador por SOAP; expira 1h;
lock de 5s tras canjear; rollback total si falla la entrega).
- /promo-code: canje de códigos por PD/PV (sensibles a mayúsculas/minúsculas,
usos limitados, 1 canje por cuenta).
- /admin/promo: panel para crear / editar / activar / desactivar / borrar
códigos de promoción.
- Tablas nuevas (sql/): home_tradecode, home_promocode, home_promoredemption.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bloqueaba /api/account/security-token (HTTP 500) y, por tanto, la activación
de 2FA. Las tablas home_* usan el id de cuenta de AzerothCore, no auth_user
(vacío tras la migración de Django). Aplicado en producción.
Co-Authored-By: Claude Opus 4.8 <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>
SumUp eliminó los webhooks, así que la acreditación no puede depender de que
el navegador vuelva al return_url. Se añade reconciliación consultando el
estado en la API de SumUp de los checkouts pendientes (fulfilled=0):
- reconcileSumUpCheckouts() en lib/sumup.ts: recorre los pendientes recientes
y acredita los que estén PAID (reclamo atómico idempotente).
- /d-points y /account reconcilian los pendientes de la cuenta al cargar, para
reflejar el saldo aunque el usuario no pasara por la página de éxito.
- /api/dpoints/reconcile: backstop global protegido con CRON_SECRET, pensado
para un systemd timer que lo llame periódicamente.
Verificado E2E con tarjeta de test: pago SumUp sin volver a la web -> el
backstop acredita los PD (idempotente). Credenciales y CRON_SECRET viven en
.env.local (fuera de git).
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>
- Reescrita la página: box «Información» con la guía completa de Recluta a un
amigo (marca → nombre del reino) + box «Panel de Recluta a un amigo».
- Nuevo RecruitPanel: estadísticas (cuenta reclutada, amigos reclutados, amigos
al nivel 80, recompensas reclamadas X/6) + tabla de recompensas (objetivo,
objeto con icono y color de calidad, estado) con botón Reclamar para las
disponibles + sección «Recompensas disponibles». Sustituye a RecruitClaim.
- lib/recruit-claim: getRecruitStats (isRecruited + recruitedCount).
- Colores de calidad de objeto .q0-.q5 en globals.css.
- Sembradas las 6 recompensas en home_recruitreward (seed en sql/).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Página al estilo del tema con instrucciones de instalación (Interface/AddOns)
y una lista de addons (nombre + descripción + botón Descargar) — set inicial de
addons populares de WotLK con enlaces a sus páginas oficiales; editable en la
constante ADDONS de la página. Devuelve 200.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>