Skip to main content

Infranete Interface

1. Descripción general

Infranete Interface es el panel de administración interno de Hawkers. El package.json no incluye campo description, por lo que esta descripción se basa en lo observado en el código.

Es una SPA Angular que centraliza la operativa interna del e-commerce y actúa como frontal de la API Infranete (https://infranete-api.hawkersco.net), compuesta por los microservicios Java/Spring Boot de Hawkers. Cubre las siguientes áreas funcionales:

  • Pedidos: consulta y edición de pedidos, resolución de errores (código postal, teléfono, DANE, sin stock), facturación (descarga y generación de facturas), branding de pedidos y gestión de emails fraudulentos.
  • Logística: métodos de envío de SFCC (Salesforce Commerce Cloud) y "Dr. Stock" (generación de Excel de stock, restringido a administradores).
  • Cupones: alta, búsqueda y borrado de cupones y sus códigos.
  • Marketplaces: pedidos por marketplace (Zalando, Decathlon…), actualización de información de Zalando y generación de reportes.
  • Feeds: feeds de imágenes, redirecciones y feeds de Google Shopping por site/país (edición de campos, protección de columnas, publicación).
  • Web: generación de JSON SEO para PLPs y actualización de stock en SFCC.
  • Reportes: reportes de estado logístico y de pedidos.

El acceso está protegido con Auth0, y la visibilidad de cada área del menú depende de los scopes presentes en el token JWT del usuario.

2. Información técnica

PropiedadValor
Nombre del paqueteinfranete-interface
Versión0.0.0 (no se versiona el paquete; el versionado real es el BUILD_NUMBER de Jenkins)
Versión de Angular^21.1.0
Versión de TypeScript~5.9.2
Gestor de paquetesnpm (packageManager: npm@11.6.2)
Tipo de proyectoAplicación única (no workspace multi-proyecto), 100 % componentes standalone, sin NgModules
RenderizadoSPA (CSR). No usa Angular Universal/SSR
Builder@angular/build:application (esbuild)
Tests unitariosVitest 4 (@angular/build:unit-test + jsdom)
FormateoPrettier (printWidth: 100, tabWidth: 4, singleQuote: true, parser angular para HTML)

3. Arquitectura y diseño

Arquitectura standalone completa: se arranca con bootstrapApplication(App, appConfig) en src/main.ts y cada componente declara sus propios imports. No existe ningún NgModule.

Estructura de src/app:

src/app/
├── app.ts / app.html / app.config.ts / app.routes.ts # shell, providers y rutas
├── components/
│ ├── shared/ # header, sidebar, breadcrumbs, footer (layout AdminLTE)
│ ├── home/ admin/
│ ├── orders/ # orders-info, order-edit, order-branding, invoices,
│ │ # order-generate-invoice, fraudulent-email (+ modales md-*)
│ ├── logistics/ # dr-stock, sfcc-shipping-methods (+ modal md-*)
│ ├── coupons/ # coupons-admin
│ ├── marketplaces/ # marketplaces-orders, zalando
│ ├── feeds/ # images-feeds, redirects, google-feeds, google-feed (+ modales md-*)
│ ├── web/ # json-seo-plp-generate, update-stock
│ └── reports/ # status-report, orders-report
├── services/ # un servicio HTTP por dominio + utilidades
├── models/ # interfaces TS por dominio (orders, coupons, feeds, auth…)
├── imports/ # barrels COMMON_IMPORTS, MATERIAL_IMPORTS, FILTER_IMPORTS
└── filters/ # SourceFilterPipe

El shell (app.html) monta un layout fijo AdminLTE 3: app-header + app-sidebar + content-wrapper con app-breadcrumbs y el router-outlet. Cada componente enrutado envuelve su contenido en <section class="content"><div class="container-fluid">….

Los componentes con prefijo md- son modales abiertos con MatDialog (p. ej. md-add-redirect, md-edit-product-line, md-add-shipping-method).

Flujo principal de autenticación y datos:

flowchart LR
U[Usuario] --> AG[AuthGuard Auth0]
AG -->|no autenticado| A0[Login Auth0]
A0 --> AG
AG -->|autenticado| C[Componente de ruta]
C --> S[Servicio de dominio]
S --> I[AuthHttpInterceptor<br/>añade JWT a /api/*]
I --> API[(infranete-api<br/>microservicios Spring Boot)]
API --> S --> C
C --> SW[AlertService / SweetAlert2]

La plantilla usa la sintaxis moderna de control de flujo de Angular (@if, @for, @switch).

4. Dependencias principales

DependenciaVersiónPropósito
@angular/*^21.1.0Framework base (core, router, forms, http)
@angular/material^21.0.6Componentes UI (diálogos, selects, autocomplete, tooltips…)
@auth0/auth0-angular^2.2.3Autenticación: AuthGuard, AuthService, AuthHttpInterceptor
admin-lte^3.2.0Layout del panel (sidebar, cards, tablas) — CSS y JS globales
rxjs~7.8.0Programación reactiva (Observable, map, timeout)
sweetalert2^11.4.8Notificaciones al usuario vía AlertService
ngx-pagination^6.0.3Paginación de tablas
jwt-decode^3.1.2Decodificar el JWT para leer los scopes en el sidebar
xlsx^0.18.5Lectura/generación de Excel en cliente (stock, reportes)
dayjs^1.11.19Manejo de fechas
bootstrap-daterangepicker^3.1.0Selector de rango de fechas (requiere jQuery y moment, cargados como scripts globales en angular.json)

No usa NgRx ni librerías internas de Hawkers.

5. Componentes y rutas

Todos los componentes son standalone y todas las rutas están protegidas con canActivate: [AuthGuard] de Auth0. Cada ruta define data.pageTitle y data.breadcrumb (consumido por Breadcrumbs).

RutaComponenteDescripción funcional
//homeHomePágina de inicio
/adminAdminUtilidades de administración
/orders-infoOrdersInfoListado/búsqueda de pedidos con información de envío
/order-brandingOrderBrandingPedidos de branding; alta de líneas de producto (modal)
/order-edit/:orderOrderEditEdición de un pedido y sus líneas (modal md-edit-product-line)
/invoicesInvoicesBúsqueda y descarga de facturas
/fraudulent-emailFraudulentEmailLista negra de emails fraudulentos (alta/baja)
/order-generate-invoice/:orderOrderGenerateInvoiceGeneración de factura para un pedido
/dr-stockDrStockGeneración de Excel de stock (visible solo con scope admin en el menú)
/sfcc-shipping-methodsSfccShippingMethodsCRUD de métodos de envío SFCC (modal md-add-shipping-method)
/coupons-adminCouponsAdminAdministración de cupones y códigos
/marketplaces-ordersMarketplacesOrdersPedidos paginados por marketplace/source
/zalandoZalandoActualización de información de Zalando
/images-feedsImagesFeedsGestión y subida de imágenes de feeds
/redirectsRedirectsGestión de redirecciones (modal md-add-redirect)
/google-feedsGoogleFeedsListado de feeds de Google por site/país
/google-feed/:site/:countryIsoGoogleFeedEdición de un feed concreto: campos, búsqueda/reemplazo, append/prepend, publicación
/update-stockUpdateStockSubida de stock a SFCC desde Excel
/json-seo-plp-generateJsonSeoPlpGenerateGeneración de JSON SEO para PLPs a partir de un Drive ID
/status-reportStatusReportReporte de estado logístico
/orders-reportOrdersReportReporte de pedidos

El Sidebar decodifica el access token con jwt-decode y muestra cada bloque del menú según el scope correspondiente (orders, web, logistics, coupons, marketplaces, feeds, reports, admin):

@if (scopes.indexOf('orders') > -1) { … }

6. Comunicación con APIs / Integraciones externas

Toda la comunicación va contra environment.baseUrl (la API Infranete). Patrón común de los servicios: const baseUrl = environment.baseUrl a nivel de fichero, HttpClient inyectado, retorno Observable<any>; los GET usan query params y los POST/PUT envían HttpParams o FormData como cuerpo.

ServicioPrefijo(s) de APIPropósito
OrderService/api/orders, /api/orders-non-stock, /api/orders-zip-error, /api/orders-phone-error, /api/orders-dane-error, /api/orders-infoCiclo de vida de pedidos: búsqueda paginada por estado, creación, cancelación, marcado como enviado/pendiente de etiqueta, reenvío a logística/Cooper, descarga y generación de facturas (responseType: 'blob')
OrderlineService/api/order-linesLíneas de pedido (valores distintos)
ShipmentService/api/sfccsmCRUD de métodos de envío SFCC
StockService/api/dr-stockGeneración de Excel de stock (responseType: 'blob')
DynamicsService/api/dynamicsAcuerdos de precios de venta (Microsoft Dynamics)
CouponService/api/couponsAlta/búsqueda/borrado de cupones y códigos
MarketplacesService/api/marketplaces, /api/zalando, /api/reportsPedidos paginados por source, actualización Zalando (timeout 300 s), reporte marketplace
FeedsService/api/images-feeds, /api/redirect-feeds, /api/google-feedsSubida de imágenes, redirecciones, edición y publicación de feeds de Google
ProductService/api/stock-sfccSubida de stock a SFCC
WebService/api/json-seo-plp-generateGeneración de JSON SEO PLP (timeout 300 s)
ReportService/api/reportsReportes de estado y de pedidos (descarga de blobs)
FraudulentEmailService/api/fraudulent-emailLista de emails fraudulentos
CountryService/api/countriesCatálogo de países
GoogleMapsServicehttps://maps.googleapis.com/maps/api/jsCarga dinámica del script de Google Maps con la API key del environment

Ejemplo representativo (OrderService):

public findPaginateByStatus(request: OrderByStatusPaginateRequest): Observable<any> {
return this.http.post(`${baseUrl}/api/orders/find-paginate-by-status`, request);
}

public generateAndDownloadInvoices(orderList: string[]): Observable<Blob> {
return this.http.post(`${baseUrl}/api/orders/generate-and-download-invoices`, orderList, {
responseType: 'blob',
});
}

Interceptor: el AuthHttpInterceptor de Auth0 (registrado en app.config.ts vía HTTP_INTERCEPTORS) adjunta automáticamente el bearer token a las peticiones que casan con environment.auth0allowedList (<baseUrl>/api/*), solicitando audience y scope configurados.

7. Gestión de estado

No hay NgRx ni store global. El enfoque es:

  • RxJS + servicios sin estado: los componentes se suscriben a los Observable de los servicios HTTP y guardan los datos en propiedades locales.
  • Signals: uso puntual (signal en App para el título); no es el mecanismo principal de estado.
  • Auth0 (AuthService) como fuente de estado de sesión (usuario, token).
  • localStorage: el Sidebar cachea los scopes del token en Base64 (clave scopes) para pintar el menú antes de que resuelva getAccessTokenSilently().

8. Configuración y entornos

Ficheros src/environments/environment.ts (dev) y environment.prod.ts. Importante: angular.json no define fileReplacements, por lo que el build siempre compila environment.ts; en CI, Jenkins sobreescribe ambos ficheros con un fichero secreto (credencial infranete-interface-env), de modo que environment.prod.ts es en la práctica redundante.

ClaveDescripciónEjemplo (dev)
productionActiva enableProdMode() en main.tsfalse
baseUrlURL base de la API Infranetehttp://localhost (prod: https://infranete-api.hawkersco.net)
apiKeyGoogleMapsAPI key de Google Maps (carga dinámica del script)********
auth0domainTenant de Auth0********
auth0clientIdClient ID de la aplicación en Auth0 (distinto por entorno)********
auth0audienceAudience del API en Auth0https://infranete-api.hawkersco.net
auth0allowedListPatrones de URL a los que el interceptor añade el token[`${baseUrl}/api/*`]
scopesScopes solicitados en el tokenopenid profile email admin commons orders logistics coupons marketplaces feeds web reports

Variables/credenciales necesarias en CI: la credencial de Jenkins infranete-interface-env (fichero de environment completo).

9. Estilos y UI

  • AdminLTE 3 como base del layout (CSS + JS globales en angular.json, junto con jQuery, moment y bootstrap-daterangepicker).
  • Angular Material con tema prebuilt indigo-pink.
  • Font Awesome para iconografía.
  • Overrides de marca Hawkers en src/styles.css: btn-hawkers / btn-outline-hawkers (verde #74c344), badge-hawkers, card-hawkers, bg-hawkers, txt-error-hawkers.
  • Convenciones: tablas con table table-bordered table-hover; modales con MatDialog; notificaciones siempre vía AlertService (SweetAlert2 con botón negro corporativo).
  • Estilos de componente inline (inlineStyle: true en schematics), con presupuesto máximo de 8 kB por componente.

10. Ejecución en local

Requisitos: Node 22 (imagen de build node:22-alpine) y npm 11.

npm install
npm start # ng serve → http://localhost:4200
  • El entorno dev apunta a baseUrl: http://localhost, por lo que se necesita la API Infranete (o un gateway) corriendo en local en el puerto 80.
  • Al abrir la app se redirige al login de Auth0 (tenant de desarrollo); tras autenticarse, el menú lateral muestra solo las secciones permitidas por los scopes del usuario.
  • Verificación: la home carga bajo /home y las llamadas a /api/* devuelven 200 con el bearer token adjunto (visible en la pestaña Network).

Otros comandos: ng build (build de producción por defecto), ng watch (build en modo desarrollo con watch), ng test (Vitest).

11. Despliegue

Pipeline declarativo de Jenkins (Jenkinsfile) con despliegue a GKE:

  1. Checkout del repositorio con workspace limpio.
  2. Environments: copia la credencial de fichero infranete-interface-env sobre src/environments/environment.ts y environment.prod.ts.
  3. Build & Push: gcloud builds submit construye la imagen Docker y la sube a Artifact Registry (europe-west3-docker.pkg.dev/pi-saldum/pi-repo/infranete-interface:BUILD_NUMBER).
  4. Deploy: elimina el deployment anterior en el namespace pi del clúster pi-cluster-hw (zona europe-west3-a), aplica k8s/deployment.yaml sustituyendo el tag latest por el del build y espera al rollout.

La imagen Docker es multi-stage: build con node:22-alpine (npm run build) y runtime con nginx:1.27-alpine, que sirve dist/infranete-interface/browser con try_files $uri $uri/ /index.html para el enrutado client-side (puerto 80).

El deployment de Kubernetes usa 1 réplica, estrategia Recreate, y límites de 256 Mi de memoria / 250m de CPU.

Job de Jenkins: https://jenkins-pi.hawkersco.net/job/infranete-interface/

12. Manejo de errores y logging

  • provideBrowserGlobalErrorListeners() en app.config.ts registra listeners globales de errores del navegador (mecanismo estándar de Angular 21). No hay ErrorHandler personalizado.
  • No hay interceptor propio de manejo de errores HTTP: cada componente gestiona el error en su suscripción y notifica al usuario mediante AlertService.alert(mensaje, 'error', …), que además puede redirigir a home o cerrar sesión en Auth0.
  • Logging solo en consola (console.error en el bootstrap de main.ts). No hay integración con Sentry ni servicios externos de logging.

13. Notas y consideraciones

  • environment.prod.ts sin efecto en el build: no hay fileReplacements en angular.json; el build siempre usa environment.ts. Funciona porque Jenkins copia el mismo fichero secreto a ambos, pero un build de producción local usaría la configuración de desarrollo. Deuda técnica a valorar.
  • Restricción de Dr. Stock: el enlace del menú solo se muestra con scope admin, pero la ruta /dr-stock está protegida únicamente por AuthGuard (autenticación); la autorización fina se delega en la API.
  • Tipado laxo en servicios: los servicios devuelven Observable<any> de forma generalizada, pese a existir modelos tipados en src/app/models.
  • Dependencias legacy globales: jQuery, moment y AdminLTE se cargan como scripts globales fuera del árbol de Angular, herencia del layout AdminLTE 3.
  • Scopes en localStorage: el sidebar cachea los scopes decodificados del JWT en Base64 para evitar parpadeo del menú; se sobreescriben al resolver getAccessTokenSilently().
  • Timeouts largos: operaciones pesadas (actualización Zalando, generación de site-list SEO) usan timeout(300000) (5 min) sobre la petición HTTP.
  • overrides.summernote: 0.9.1 en package.json fija la versión de summernote (dependencia transitiva de AdminLTE) — probablemente por una vulnerabilidad o incompatibilidad. Pendiente de verificar el motivo.
  • No se han encontrado comentarios TODO/FIXME en el código fuente.
  • El proyecto no define description ni versión significativa en package.json.