refactor(web): page state with its page, the root keeps the shell's

Only what the header needs from the start stays at the root: the
session, my projects for the command palette, the inbox and push for
the bell, and their adapters. The home page's facades (my work, the
rest of the home, my views, the calendar), Explore's and the proposal
form's are provided by their routes, whose injectors keep them for
when you come back. The other adapters come with the tracker's routes,
now loaded lazily.

The web libs declare "sideEffects": false, so a chunk carries what it
uses and not everything an index.ts exports: main goes from 1.31 MB
to 432 kB of the same initial total, which is still held up by @pi/ui
(one module, with all of Material) and the GraphQL documents, both
needed by the header.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-16 08:34:17 +02:00
parent d0efaeba80
commit f448207e88
22 changed files with 160 additions and 47 deletions

View File

@@ -113,18 +113,30 @@ Qué gana la página:
| ---------------- | --------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `AuthFacade` | `AuthStore` | raíz | Sesión, usuario, login (PKCE o email y contraseña de Pireon), renovación del token, restaurar al arrancar |
| `ProjectsFacade` | `ProjectsStore` | raíz | Mis proyectos; se actualiza cuando me añaden o quitan (`myProjectsChanged`) |
| `HomeFacade` | `HomeStore` | raíz | «Mi trabajo» en la portada: mis tickets abiertos por categoría (QA fallidos primero), esperando QA y próximas releases; se recarga al volver a la pestaña |
| `MyHomeFacade` | `MyHomeStore` | raíz | El resto de la portada (`myHome`): agenda, actividad, cifras de la semana, sprints, tarjetas, sugerencias, primeros pasos y quién está; se recarga cada minuto y al volver a la pestaña |
| `MyViewsFacade` | `MyViewsStore` | raíz | Mis vistas guardadas de «Mi trabajo» (entre proyectos: proyectos, asignados a mí, que sigo, estados, prioridades, solo bugs, vencidos, texto) y los tickets de la elegida |
| `ExploreFacade` | `ExploreStore` | raíz | Proyectos públicos («Explorar»), también sin sesión |
| `HomeFacade` | `HomeStore` | ruta `/` (portada) | «Mi trabajo» en la portada: mis tickets abiertos por categoría (QA fallidos primero), esperando QA y próximas releases; se recarga al volver a la pestaña |
| `MyHomeFacade` | `MyHomeStore` | ruta `/` (portada) | El resto de la portada (`myHome`): agenda, actividad, cifras de la semana, sprints, tarjetas, sugerencias, primeros pasos y quién está; se recarga cada minuto y al volver a la pestaña |
| `MyViewsFacade` | `MyViewsStore` | ruta `/` (portada) | Mis vistas guardadas de «Mi trabajo» (entre proyectos: proyectos, asignados a mí, que sigo, estados, prioridades, solo bugs, vencidos, texto) y los tickets de la elegida |
| `ExploreFacade` | `ExploreStore` | ruta `explore` | Proyectos públicos («Explorar»), también sin sesión |
| `ProjectFacade` | `ProjectStore` | ruta `/p/:key` | Proyecto, miembros, stats, releases, actividad en vivo, búsqueda de usuarios, configuración (`workflow`, `saveSettings`) y estadísticas (`loadAnalytics`, `loadBurnup`) |
| `BoardFacade` | `BoardStore` | ruta `board` | Tablero kanban, filtros, movimiento optimista, nuevo ticket, cambios en vivo |
| `ListFacade` | `ListStore` | ruta `list` | Todos los tickets del proyecto en filas: filtros (enviados a la API), cambios de estado, prioridad y persona en la fila, edición en bloque; se recarga tras cada cambio propio y con los de otros |
| `IssueFacade` | `IssueStore` | ruta `issues/:issueKey` | Ticket, comentarios en vivo, historial y todas sus acciones |
Las de ámbito de ruta se registran con `provideProjectFacade()`, `provideBoardFacade()` o `provideIssueFacade()` en los
`providers` del componente de la página (store + facade) y desaparecen al salir (con sus subscriptions). Las páginas
hijas de `/p/:key` reciben la misma `ProjectFacade`.
En la raíz solo queda lo que usa la cabecera desde el arranque: la sesión (`AuthFacade`), mis proyectos para la paleta
de comandos (`ProjectsFacade`) y la campana (`InboxFacade`, `PushFacade`). Lo demás es de su página:
- Las de una página que se vuelve a visitar a menudo (portada, Explorar, el formulario de propuestas) van en los
`providers` de su ruta (`provideHomeFacade()`, `provideMyHomeFacade()`, `provideMyViewsFacade()`,
`provideCalendarFacade()`, `provideExploreFacade()`, `provideProposeFacade()`): cargan con la página y el inyector de
la ruta las conserva, así que al volver se ve lo último al instante mientras se recarga.
- Las de un proyecto o un ticket se registran con `provideProjectFacade()`, `provideBoardFacade()` o
`provideIssueFacade()` en los `providers` del componente de la página (store + facade) y desaparecen al salir (con sus
subscriptions). Las páginas hijas de `/p/:key` reciben la misma `ProjectFacade`.
Los adaptadores siguen el mismo reparto: `provideTrackerShellInfrastructure()` (proyectos, tickets, avisos, push y tiempo
real) va en la raíz, y `provideTrackerPagesInfrastructure()` (el resto) en la ruta del tracker, que se carga en diferido
(`apps/web/src/app/tracker.routes.ts`). Las librerías web declaran `"sideEffects": false` (`libs/web/package.json`), para
que el empaquetador deje en cada trozo solo lo que usa y no todo lo que exporta un `index.ts`.
Otros contextos también usan la facade: los stores del tracker leen el usuario de `AuthFacade`, y la infraestructura
de identidad (`SessionTokenSource`) le pide el token para el cliente GraphQL.