Autor: Iker Acevedo¶
Fecha creacion: 2026-10-17 Estado: propuesta (pendiente de aprobación) Tipo: estándar obligatorio
Crear una vista¶
Aplica a toda vista nueva desde que se apruebe el estándar, y a toda vista existente que se migre (ver Migración de vistas).
1. Orden de trabajo¶
Primero la lógica, después lo visual:
models/: tipos de la vista.repository/: llamadas al API (con las reglas de seguridad por diseño).helpers/: reglas puras con sus pruebas.state/: store y facade, con pruebas del facade.<vista>.page.tsy<vista>.experiencias.ts.experiencias/clasica/: la versión obligatoria.- Versiones para otras experiencias, cuando el diseño exista.
- Ficha de documentación con la plantilla.
2. Ruta¶
{
path: 'pedidos',
loadComponent: () => import('./pedidos/pedidos.page').then(m => m.PedidosPage),
data: { title: 'Pedidos', vista: 'tienda.pedidos' },
}
La URL es la misma en todas las experiencias. Una experiencia nunca agrega ni cambia rutas.
3. Registro de versiones¶
// pedidos.experiencias.ts
import { VersionesVista } from '@core/experiencias/experiencias.models';
export const VERSIONES_PEDIDOS: VersionesVista = {
vista: 'tienda.pedidos',
versiones: {
clasica: () => import('./experiencias/clasica/pedidos-clasica.component').then(m => m.PedidosClasicaComponent),
// Se agrega una línea por cada experiencia que tenga versión propia de esta vista.
},
};
El tipo VersionesVista exige clasica y solo acepta ids de experiencias registradas, así que un error de
escritura no compila:
// core/experiencias/experiencias.models.ts
export type CargadorComponente = () => Promise<Type<unknown>>;
export interface VersionesVista {
vista: string;
versiones: { clasica: CargadorComponente } & Partial<Record<ExperienciaId, CargadorComponente>>;
}
4. Página (host)¶
// pedidos.page.ts
@Component({
selector: 'app-pedidos-page',
imports: [NgComponentOutlet, CargandoVistaComponent],
providers: [PedidosStore, PedidosFacade], // el cerebro vive y muere con la página
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
@if (version(); as componente) {
<ng-container *ngComponentOutlet="componente" />
} @else {
<app-cargando-vista />
}
`,
})
export class PedidosPage {
protected readonly version = versionActiva(VERSIONES_PEDIDOS);
constructor() {
inject(PedidosFacade).iniciar();
}
}
versionActiva() devuelve la versión de la experiencia activa o, si no existe, la clasica (respaldo).
La página casi no tiene código y es igual en todas las vistas.
5. Facade y versión visual¶
// state/pedidos.facade.ts
@Injectable()
export class PedidosFacade {
private readonly repository = inject(PedidosRepository);
private readonly store = inject(PedidosStore);
// Lecturas: las versiones visuales solo leen
readonly cargando = this.store.cargando;
readonly filas = this.store.filasVisibles;
readonly resumen = this.store.resumenPorEstado;
readonly permisos = this.store.permisos;
// Acciones: las versiones visuales solo llaman
async iniciar(): Promise<void> { /* repository -> store */ }
aplicarFiltros(cambio: Partial<FiltrosPedidos>): void { /* ... */ }
seleccionarEstado(estado: EstadoPedido | null): void { /* ... */ }
}
// experiencias/clasica/pedidos-clasica.component.ts
@Component({
selector: 'app-pedidos-clasica',
imports: [ClasicaTarjetaComponent, ClasicaTablaComponent],
templateUrl: './pedidos-clasica.component.html',
styleUrl: './pedidos-clasica.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PedidosClasicaComponent {
protected readonly pedidos = inject(PedidosFacade);
/** Estado solo visual. */
protected readonly filtrosAbiertos = signal(false);
}
6. Prohibiciones en una versión visual¶
Una carpeta experiencias/<id>/ de una vista no puede:
- Inyectar
Repository,Store,HttpClient,ConsumoGenericoServiceni servicios de datos. - Leer o escribir
sessionStorageolocalStorage. - Decidir permisos con nombres de rol. Usa
facade.permisos(). - Calcular reglas de negocio (totales, conteos, filtros, formatos de moneda). Van en
helpers/. - Usar colores fijos (
#hex,rgb()),!importanto::ng-deepnuevo. - Importar archivos de otra experiencia.
- Usar
innerHTMLobypassSecurityTrust*con datos del usuario o del API.
7. Pruebas mínimas¶
| Qué | Cómo |
|---|---|
helpers/ |
Una prueba por regla, sin TestBed |
state/*.facade.ts |
Con repository falso: iniciar, cada acción, errores |
| Cada versión visual | Se monta con un facade falso y pinta sin errores |
| Registro | Cada cargador resuelve a un componente |
8. Checklist de terminado¶
- [ ] La ruta usa
<vista>.page.tsy declaradata.vista. - [ ] Existe
experiencias/clasica/. - [ ] Ninguna versión rompe las prohibiciones de la sección 6 (ESLint en verde).
- [ ] Las reglas de negocio están en
helpers/con pruebas. - [ ] Los permisos de la vista se calculan en un solo lugar del facade.
- [ ] El SCSS usa solo tokens (Stylelint en verde).
- [ ] Cumple la seguridad por diseño.
- [ ] Ficha de la vista creada y entrada en el changelog.
Historial de cambios¶
| Fecha | Autor | Cambio |
|---|---|---|
| 2026-10-17 | Iker Acevedo | Creación de la propuesta |