Implementar scope extensions y link handling para PWAs
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 56s
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 56s
- 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
This commit is contained in:
254
PWA_SCOPE_EXTENSIONS.md
Normal file
254
PWA_SCOPE_EXTENSIONS.md
Normal file
@@ -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
|
||||||
@@ -28,7 +28,8 @@ services:
|
|||||||
- "traefik.http.services.${APP_NAME}.loadbalancer.server.port=3000"
|
- "traefik.http.services.${APP_NAME}.loadbalancer.server.port=3000"
|
||||||
|
|
||||||
# Router 1: Public PWA resources (no auth) - Higher priority
|
# 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.entrypoints=websecure"
|
||||||
- "traefik.http.routers.${APP_NAME}-public.tls.certresolver=letsencrypt"
|
- "traefik.http.routers.${APP_NAME}-public.tls.certresolver=letsencrypt"
|
||||||
- "traefik.http.routers.${APP_NAME}-public.priority=100"
|
- "traefik.http.routers.${APP_NAME}-public.priority=100"
|
||||||
|
|||||||
@@ -43,6 +43,27 @@ export default defineNuxtConfig({
|
|||||||
start_url: '/?source=pwa',
|
start_url: '/?source=pwa',
|
||||||
// Capturar todos los enlaces que apunten a esta app
|
// Capturar todos los enlaces que apunten a esta app
|
||||||
capture_links: 'existing-client-navigate',
|
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: [
|
icons: [
|
||||||
{
|
{
|
||||||
src: '/icon-192x192.png',
|
src: '/icon-192x192.png',
|
||||||
|
|||||||
Reference in New Issue
Block a user