hawkers-redirect-api
1. Descripción general
Según el pom.xml, el proyecto se describe como "Hawkers redirect Api". Es una API web que redirige (HTTP 301) peticiones recibidas en dominios legacy o alias (p. ej. hawkers.co, northweek.co, hawkersmexico.com) hacia su dominio canónico correspondiente en hawkersco.com/northweek.com, preservando la ruta original. Además, resuelve URLs cortas de los dominios hawke.rs y nweek.eu consultando una base de datos de redirecciones (no solo un mapa estático en memoria).
El CLAUDE.md del repositorio describe el servicio como puramente estático ("no database, no cache, and no external service calls — just a static HashMap"), pero esto ya no refleja el código actual (ver hallazgo en la sección 13): existe una integración JPA activa contra la base de datos feeds para resolver los códigos cortos de hawke.rs/nweek.eu.
2. Información técnica
| Campo | Valor |
|---|---|
artifactId | hawkers-redirect-api |
groupId | com.hawkersco |
version | 1.0.25 |
| Java | 25 (maven.compiler.release=25) |
| Spring Boot | 4.0.6 |
| Tipo de artefacto | jar (ejecutable, API web de larga duración) |
| Módulos | No aplica (proyecto de módulo único) |
3. Arquitectura y diseño
API REST minimalista con un único controlador y una única regla de negocio (resolución de destino de redirección).
com.hawkersco.hawkersredirectapi— clase principal (HawkersRedirectApiApplication, con@EnableJpaRepositories("com.hawkersco.feedscommons.repository")) yHawkersRedirectApiController..config—HawkersRedirectApiConfiguration(bean manualHawkeRsRedirectionServicedefeeds-commons+PersistenceManagedTypessobrecom.hawkersco.feedscommons.dao).
flowchart TD
A[GET ** con Host header] --> B{Host contiene hawke.rs o nweek.eu?}
B -- Sí --> C[HawkeRsRedirectionService.findTop1ByCodeAndSite]
C -->|encontrado| D[redirect: url almacenada en BD]
C -->|no encontrado| E["redirect: https://www.hawkersco.com"]
B -- No --> F{Host está en REDIRECTION_MAP estático?}
F -- Sí --> G[redirect: destino mapeado + path]
F -- No --> E
4. Dependencias principales
| Dependencia | Propósito |
|---|---|
spring-boot-starter-web | Exposición del endpoint catch-all y del health check |
com.hawkersco:feeds-commons:1.0.25-SNAPSHOT | HawkeRsRedirectionService + entidades JPA de la BD feeds para resolver códigos cortos |
spring-boot-starter-test (test) | JUnit 5 + Spring Test |
5. API / Endpoints
| Método | Ruta | Descripción |
|---|---|---|
GET | /check-domain | Health check; devuelve 200 OK con cuerpo "OK" |
GET | /** (catch-all) | Resuelve el destino de redirección según el Host de la petición y responde con un 301 (vista redirect:) hacia la URL resuelta, preservando el path original |
Lógica de resolución (por orden de prioridad):
- Si el
Hostcontienehawke.rs→ busca el código (path sin la barra inicial) enHawkeRsRedirectionService.findTop1ByCodeAndSite(code, "hawkers"). - Si el
Hostcontienenweek.eu→ misma búsqueda consite = "northweek". - En cualquier otro caso, busca el
Host(con o sin prefijowww.) en el mapa estáticoREDIRECTION_MAP(14 entradas:hawkers.co,hawkersaustralia.com,hawkersco.co.uk,northweek.com,northweek.co,hawkersmexico.com,hawkerscolombia.co,hawkersgroup.com,misshamptons.com,lentillas.hawkersco.com,lentedecontato.hawkersco.com,lentesdecontato.hawkersco.com,hawkers213.com,hawkers2013.com,gafasdesol.com). - Si no hay coincidencia en ninguno de los pasos anteriores, redirige a
https://www.hawkersco.com(+ path).
6. Integraciones externas
| Sistema | Protocolo | Dirección | Detalle |
|---|---|---|---|
PostgreSQL (feeds) | JDBC | Entrante | Resolución de códigos cortos hawke.rs/nweek.eu vía HawkeRsRedirectionService |
7. Configuración
En producción (application-pro.properties) las credenciales llegan por variables de entorno inyectadas como Secret de Kubernetes; en local (application.properties) el repositorio contiene actualmente valores reales hardcodeados (ver alerta de seguridad).
| Clave | Descripción | Ejemplo (producción) |
|---|---|---|
server.port | Puerto HTTP del servicio | 80 |
spring.datasource.url | URL JDBC de la BD feeds | ${dbFeedsUrl} |
spring.datasource.username / .password | Credenciales de BD | ${dbFeedsUsername} / ${dbFeedsPassword} |
logging.level.* | Ajustes de nivel de log para reducir ruido de Tomcat/MVC | ERROR / WARN |
⚠️ Alerta de seguridad
El fichero src/main/resources/application.properties (perfil local) contiene actualmente la contraseña real en texto plano de la base de datos PostgreSQL feeds. No se ha reproducido en este documento. Se recomienda:
- Rotar la contraseña de la base de datos expuesta.
- Sustituir el valor hardcodeado por credenciales de un entorno de desarrollo aislado.
- Revisar el historial de control de versiones, ya que esta credencial puede seguir expuesta en commits anteriores.
8. Persistencia
Base de datos PostgreSQL feeds, acceso vía JPA a través de la librería feeds-commons (@EnableJpaRepositories("com.hawkersco.feedscommons.repository")). spring.jpa.hibernate.ddl-auto=none. Entidad relevante: la tabla de redirecciones consultada por HawkeRsRedirectionService.findTop1ByCodeAndSite(code, site), distinguiendo entre site = "hawkers" (dominio hawke.rs) y site = "northweek" (dominio nweek.eu). No hay Flyway/Liquibase en este repositorio.
9. Procesos programados y mensajería
No aplica a este proyecto. Es puramente reactivo a las peticiones HTTP entrantes; no hay @Scheduled ni listeners de colas.
10. Ejecución en local
Requisitos previos: JDK 25, Maven, acceso a la BD feeds.
# Compilar
./mvnw clean install
# Ejecutar tests
./mvnw test
# Ejecutar la aplicación localmente (puerto 80, puede requerir sudo)
./mvnw spring-boot:run
# Build Docker
docker build -t hawkers-redirect-api:latest .
docker run -p 80:80 hawkers-redirect-api:latest
Verificación de que el servicio está operativo: GET /check-domain devuelve 200 OK con cuerpo "OK". No hay Actuator configurado.
11. Despliegue
- Imagen: construida con
jib-maven-plugin(baseeclipse-temurin:25-jre,containerizingMode=packaged), publicada eneurope-west3-docker.pkg.dev/pi-saldum/pi-repo/hawkers-redirect-api:<tag>. - Orquestación: Kubernetes
Deployment(k8s/deployment.yaml, noCronJob), replicado 13 veces con nombres distintos a partir de la misma imagen/manifiesto (hawkers-redirect-api,-eyewear,-hawke-rs,-hawkers,-hawkersaustralia,-hawkersco,-hawkerscolombia,-hawkersgroup,-hawkersmexico,-lens,-misshamptons,-northweek-co,-northweek), todos en el clúster GKEpi-cluster-hw(zonaeurope-west3-a, proyectopi-saldum), namespacepi,replicas: 1cada uno. Ver nota sobre esta redundancia en la sección 13. - CI/CD (Jenkins): pipeline con 2 etapas —
Checkout→Build & Push(sustituyeapplication-pro.propertiesporapplication.properties) →Deploy to GKE, que en un bucle Groovy aplica el mismo manifiesto templado 13 veces (una por cada nombre deDeploymentde la lista) y espera elrollout statusde cada uno. - Todos los
Deploymentcomparten el mismoSecretde Kuberneteshawkers-redirect-api(nombre fijo, no parametrizado porAPP_NAMEa diferencia del resto de claves del manifiesto).
Job de Jenkins: https://jenkins-pi.hawkersco.net/job/hawkers-redirect-api/
12. Manejo de errores y logging
No hay manejo de excepciones propio: el controlador siempre resuelve a una URL válida (con fallback a https://www.hawkersco.com), por lo que no hay caminos de error de negocio. Los niveles de log de DefaultHandlerExceptionResolver y Http11Processor se han rebajado explícitamente (ERROR/WARN) para reducir ruido en consola. No hay @RestControllerAdvice ni notificación a Slack/otro canal.
13. Notas y consideraciones
CLAUDE.mddesactualizado en un punto central de la arquitectura: afirma explícitamente que el servicio "no tiene base de datos, ni caché, ni llamadas a servicios externos — solo unHashMapestático", pero el código actual sí tiene una dependencia activa defeeds-commons, un datasource JPA configurado (@EnableJpaRepositories) y una ruta de resolución de URLs cortas contra base de datos para los dominioshawke.rs/nweek.eu, que ni siquiera se menciona en el documento. Es la discrepancia más relevante encontrada en este proyecto; se recomienda regenerar elCLAUDE.md.- 13 despliegues idénticos de la misma imagen: el
Jenkinsfiledespliega el mismo artefacto 13 veces bajo nombres deDeploymentdistintos (uno por dominio/alias, aparentemente), a pesar de que el propio controlador ya resuelve el destino según el headerHostde la petición dentro de un único proceso. Es probable que exista una razón de infraestructura (DNS/Ingress apuntando a servicios distintos, aislamiento de logs/métricas por dominio, o migración histórica), pero desde el punto de vista del código es redundante: una sola instancia podría atender todos los dominios igual que ya hace en local. Pendiente de verificar con el equipo de infraestructura si esta redundancia es intencional. - Normalización de host inconsistente entre rutas: para el mapa estático, el
Hostse compara en minúsculas y con/sin prefijowww.; para la resolución dehawke.rs/nweek.eu, solo se comprueba que el host (ya en minúsculas) contenga la cadena del dominio, sin normalizarwww.— comportamiento coherente en la práctica dado que ambos dominios cortos no suelen usarse conwww., pero merece una prueba explícita si se añadieran variantes. - Ver alerta de seguridad en la sección 7 sobre la contraseña real de base de datos expuesta en
application.properties.