From 147fa4df32b9547b528ae3a5bfbcd3cb1ad1b760 Mon Sep 17 00:00:00 2001 From: josedario87 Date: Fri, 17 Oct 2025 02:14:02 -0600 Subject: [PATCH] Implementar scope extensions y link handling para PWAs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Agregar scope_extensions en manifest para capturar navegaciones a otros subdominios - Configurar Traefik para servir archivos .well-known sin autenticación - Documentar configuración completa del sistema --- PWA_SCOPE_EXTENSIONS.md | 254 ++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 3 +- nuxt4/nuxt.config.ts | 21 ++++ 3 files changed, 277 insertions(+), 1 deletion(-) create mode 100644 PWA_SCOPE_EXTENSIONS.md diff --git a/PWA_SCOPE_EXTENSIONS.md b/PWA_SCOPE_EXTENSIONS.md new file mode 100644 index 0000000..cc37cfb --- /dev/null +++ b/PWA_SCOPE_EXTENSIONS.md @@ -0,0 +1,254 @@ +# Configuración de Scope Extensions y Link Handling en Nucleo V3 + +## Resumen + +Este documento describe la implementación de **Scope Extensions** y **Link Handling** en las PWAs del ecosistema Nucleo V3, permitiendo que múltiples aplicaciones web en diferentes subdominios funcionen como un sistema unificado de aplicaciones progresivas. + +## ¿Qué son Scope Extensions? + +Scope Extensions es una característica de las Progressive Web Apps que permite a una PWA extender su scope (alcance) a otros orígenes (dominios/subdominios). Esto significa que: + +- Una PWA instalada puede "capturar" navegaciones a otros subdominios +- Los usuarios pueden moverse entre apps manteniendo la experiencia de PWA +- El ecosistema de apps se siente más integrado y cohesivo + +## Arquitectura Implementada + +### Hub Principal: Perfil PWA + +La aplicación **perfil** (`inicio.nucleoriofrio.com`) actúa como el **hub principal** del ecosistema Nucleo V3, con la capacidad de capturar navegaciones a: + +- `musica.nucleoriofrio.com` (RepoDructor) +- `docs.nucleoriofrio.com` (Nucleo Docs) +- `analitica.nucleoriofrio.com` (Analítica Nucleo) +- `seguidordelotes.nucleoriofrio.com` (Seguidor de Lotes) +- `whisper.nucleoriofrio.com` (Nucleo Whisper) +- `amigos.nucleoriofrio.com` (Amigos App) + +### Apps Secundarias + +Cada app secundaria puede: +- Funcionar de manera independiente como PWA +- Confirmar su asociación con la PWA de Perfil mediante archivos `.well-known` +- Capturar enlaces dentro de su propio scope + +## Componentes de la Implementación + +### 1. Manifests (nuxt.config.ts) + +#### Perfil (Hub Principal) +```typescript +manifest: { + // ... otras propiedades ... + capture_links: 'existing-client-navigate', + scope_extensions: [ + { origin: "https://musica.nucleoriofrio.com" }, + { origin: "https://docs.nucleoriofrio.com" }, + { origin: "https://analitica.nucleoriofrio.com" }, + { origin: "https://seguidordelotes.nucleoriofrio.com" }, + { origin: "https://whisper.nucleoriofrio.com" }, + { origin: "https://amigos.nucleoriofrio.com" } + ] +} +``` + +#### Apps Secundarias +```typescript +manifest: { + // ... otras propiedades ... + capture_links: 'existing-client-navigate' +} +``` + +### 2. Archivos .well-known/web-app-origin-association + +Cada app secundaria debe tener este archivo en `public/.well-known/web-app-origin-association`: + +```json +{ + "web_apps": [ + { + "manifest": "https://inicio.nucleoriofrio.com/manifest.webmanifest", + "details": { + "paths": ["/*"] + } + } + ] +} +``` + +**Ubicaciones:** +- `/home/draganel/repos/repodructor/public/.well-known/web-app-origin-association` +- `/home/draganel/repos/nucleoDocs/nuxt4/public/.well-known/web-app-origin-association` +- `/home/draganel/repos/nucleoWhisper/nuxt4/public/.well-known/web-app-origin-association` +- `/home/draganel/repos/analiticaNucleo/nuxt4-app/public/.well-known/web-app-origin-association` +- `/home/draganel/repos/seguidorDeLotes/nuxt4-app/public/.well-known/web-app-origin-association` + +### 3. Configuración de Traefik (docker-compose.yml) + +Cada `docker-compose.yml` ha sido actualizado para servir los archivos `.well-known` **sin autenticación**, con alta prioridad: + +```yaml +# Router público para recursos PWA (sin autenticación) +- "traefik.http.routers.${APP_NAME}-public.rule=Host(`${APP_DOMAIN}`) && (PathPrefix(`/.well-known`) || PathPrefix(`/manifest.webmanifest`) || ...)" +- "traefik.http.routers.${APP_NAME}-public.priority=100" +``` + +## Flujo de Usuario + +1. **Instalación de Perfil PWA** + - Usuario instala la PWA de Perfil desde `inicio.nucleoriofrio.com` + - El navegador lee el manifest y detecta los `scope_extensions` + - El navegador valida automáticamente los archivos `.well-known` en cada origen extendido + +2. **Navegación entre Apps** + - Usuario hace clic en un enlace a `musica.nucleoriofrio.com` desde cualquier app + - Si la PWA de Perfil está instalada y configurada correctamente: + - El navegador puede abrir el enlace dentro de la ventana de la PWA + - En lugar de abrir el navegador normal + - La experiencia es más fluida y cohesiva + +3. **Apps Independientes** + - Cada app puede seguir siendo instalada independientemente + - Cada app mantiene su propio Service Worker y caché + - Las apps pueden funcionar offline según su configuración individual + +## Limitaciones Técnicas + +### Same-Origin Policy +Aunque las apps comparten el link handling, **NO comparten**: +- Service Workers (cada origen tiene el suyo) +- Caches (cada origen tiene su propio cache storage) +- Almacenamiento local (localStorage, IndexedDB) +- Permisos (cada origen pide permisos independientemente) + +### Soporte de Navegadores +- **Chromium-based browsers** (Chrome, Edge): Soporte completo +- **Firefox**: Soporte limitado o experimental +- **Safari**: Sin soporte actualmente + +## Validación y Testing + +### Verificar Implementación + +1. **Verificar archivos .well-known:** +```bash +# Debe devolver el JSON de asociación +curl https://musica.nucleoriofrio.com/.well-known/web-app-origin-association +``` + +2. **Verificar manifest de Perfil:** +```bash +# Debe contener scope_extensions +curl https://inicio.nucleoriofrio.com/manifest.webmanifest | grep scope_extensions +``` + +3. **Instalar y probar:** + - Instalar la PWA de Perfil en Chrome/Edge + - Hacer clic en enlaces a otras apps del ecosistema + - Verificar que se abren dentro de la ventana de la PWA + +### Debugging + +**Chrome DevTools:** +1. Abrir DevTools → Application → Manifest +2. Verificar que `scope_extensions` aparece correctamente +3. En la consola, verificar errores relacionados con `.well-known` + +**Edge DevTools:** +Similar a Chrome, con soporte adicional para PWA features + +## Mantenimiento + +### Agregar una Nueva App al Ecosistema + +1. **Actualizar el manifest de Perfil** (`/home/draganel/repos/perfil/nuxt4/nuxt.config.ts`): +```typescript +scope_extensions: [ + // ... extensiones existentes ... + { + origin: "https://nuevaapp.nucleoriofrio.com" + } +] +``` + +2. **Crear `.well-known` en la nueva app**: +```bash +mkdir -p /ruta/a/nuevaapp/public/.well-known +``` + +Crear `/ruta/a/nuevaapp/public/.well-known/web-app-origin-association`: +```json +{ + "web_apps": [ + { + "manifest": "https://inicio.nucleoriofrio.com/manifest.webmanifest", + "details": { + "paths": ["/*"] + } + } + ] +} +``` + +3. **Actualizar docker-compose.yml** de la nueva app: +```yaml +- "traefik.http.routers.nuevaapp-public.rule=Host(`nuevaapp.nucleoriofrio.com`) && (PathPrefix(`/.well-known`) || ...)" +``` + +4. **Agregar capture_links** al manifest de la nueva app: +```typescript +manifest: { + // ... otras propiedades ... + capture_links: 'existing-client-navigate' +} +``` + +### Remover una App del Ecosistema + +1. Remover el origen de `scope_extensions` en el manifest de Perfil +2. Eliminar el archivo `.well-known` de la app +3. Rebuild y redeploy ambas apps + +## Archivos Modificados + +### Manifests Actualizados +- ✅ `/home/draganel/repos/perfil/nuxt4/nuxt.config.ts` +- ✅ `/home/draganel/repos/repodructor/nuxt.config.ts` +- ✅ `/home/draganel/repos/nucleoDocs/nuxt4/nuxt.config.ts` +- ✅ `/home/draganel/repos/nucleoWhisper/nuxt4/nuxt.config.ts` +- ✅ `/home/draganel/repos/analiticaNucleo/nuxt4-app/nuxt.config.ts` +- ✅ `/home/draganel/repos/seguidorDeLotes/nuxt4-app/nuxt.config.ts` + +### Archivos .well-known Creados +- ✅ `/home/draganel/repos/repodructor/public/.well-known/web-app-origin-association` +- ✅ `/home/draganel/repos/nucleoDocs/nuxt4/public/.well-known/web-app-origin-association` +- ✅ `/home/draganel/repos/nucleoWhisper/nuxt4/public/.well-known/web-app-origin-association` +- ✅ `/home/draganel/repos/analiticaNucleo/nuxt4-app/public/.well-known/web-app-origin-association` +- ✅ `/home/draganel/repos/seguidorDeLotes/nuxt4-app/public/.well-known/web-app-origin-association` + +### Docker Compose Actualizados +- ✅ `/home/draganel/repos/perfil/docker-compose.yml` +- ✅ `/home/draganel/repos/repodructor/docker-compose.yml` +- ✅ `/home/draganel/repos/nucleoDocs/docker-compose.yml` +- ✅ `/home/draganel/repos/nucleoWhisper/docker-compose.yml` +- ✅ `/home/draganel/repos/analiticaNucleo/docker-compose.yml` +- ✅ `/home/draganel/repos/seguidorDeLotes/docker-compose.yml` + +## Referencias + +- [Building multiple Progressive Web Apps on the same domain - Google](https://web.dev/building-multiple-pwas/) +- [Handle links to a PWA - Microsoft Edge Developer](https://docs.microsoft.com/en-us/microsoft-edge/progressive-web-apps-chromium/how-to/handle-links) +- [Scope Extensions for Web App Manifest - W3C](https://github.com/WICG/manifest-incubations/blob/gh-pages/scope_extensions-explainer.md) + +## Soporte + +Para problemas o preguntas sobre esta configuración, contactar a: +- **Desarrollador:** Dario (Leouch, Draganel, nucleo000) +- **Empresa:** Nucleo Rio Frio + +--- + +**Fecha de implementación:** 2025-10-17 +**Versión:** 1.0 +**Sistema:** Nucleo V3 diff --git a/docker-compose.yml b/docker-compose.yml index aa3847d..fe70ea9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -28,7 +28,8 @@ services: - "traefik.http.services.${APP_NAME}.loadbalancer.server.port=3000" # Router 1: Public PWA resources (no auth) - Higher priority - - "traefik.http.routers.${APP_NAME}-public.rule=Host(`${APP_DOMAIN}`) && (PathPrefix(`/manifest.webmanifest`) || PathPrefix(`/sw.js`) || PathPrefix(`/workbox-`) || PathPrefix(`/icon-`) || PathPrefix(`/apple-touch-icon`) || PathPrefix(`/favicon.ico`) || PathPrefix(`/robots.txt`) || PathPrefix(`/offline.html`) || PathPrefix(`/api/_nuxt_icon/`))" + # Incluye .well-known para scope extensions + - "traefik.http.routers.${APP_NAME}-public.rule=Host(`${APP_DOMAIN}`) && (PathPrefix(`/.well-known`) || PathPrefix(`/manifest.webmanifest`) || PathPrefix(`/sw.js`) || PathPrefix(`/workbox-`) || PathPrefix(`/icon-`) || PathPrefix(`/apple-touch-icon`) || PathPrefix(`/favicon.ico`) || PathPrefix(`/robots.txt`) || PathPrefix(`/offline.html`) || PathPrefix(`/api/_nuxt_icon/`))" - "traefik.http.routers.${APP_NAME}-public.entrypoints=websecure" - "traefik.http.routers.${APP_NAME}-public.tls.certresolver=letsencrypt" - "traefik.http.routers.${APP_NAME}-public.priority=100" diff --git a/nuxt4/nuxt.config.ts b/nuxt4/nuxt.config.ts index ae82b4e..d72be7d 100644 --- a/nuxt4/nuxt.config.ts +++ b/nuxt4/nuxt.config.ts @@ -43,6 +43,27 @@ export default defineNuxtConfig({ start_url: '/?source=pwa', // Capturar todos los enlaces que apunten a esta app capture_links: 'existing-client-navigate', + // Extender scope a otros subdominios de Nucleo V3 + scope_extensions: [ + { + origin: "https://musica.nucleoriofrio.com" + }, + { + origin: "https://docs.nucleoriofrio.com" + }, + { + origin: "https://analitica.nucleoriofrio.com" + }, + { + origin: "https://seguidordelotes.nucleoriofrio.com" + }, + { + origin: "https://whisper.nucleoriofrio.com" + }, + { + origin: "https://amigos.nucleoriofrio.com" + } + ], icons: [ { src: '/icon-192x192.png',