Versión: 4.0 (Alineada con Estándares Master)
Estado: NORMATIVO
Referencia Obligatoria: ESTANDARES_DESARROLLO.md (La Biblia).
El frontend de Nebula no es una colección de páginas HTML. Es una Aplicación de Ingeniería.
NgModules para nuevos desarrollos. Todo componente debe ser standalone: true.signal, computed, effect) en lugar de Zone.js implícito.@Input) y emitir eventos (@Output). Toda la lógica de negocio y llamadas HTTP viven en el Service.src/app
├── core # SINGLETONS (Simappe Legacy & Guards)
│ ├── auth # Interceptores JWT, Guards
│ ├── layout # Navbar, Sidebar, Footer components
│ └── models # Modelos globales (User, Config)
├── shared # REUTILIZABLES (Centrica Shared)
│ ├── ui # Componentes tontos (Botones, Tablas, Inputs)
│ ├── pipes # Formato de moneda, fechas
│ └── directives # Permisos, validaciones visuales
└── features # MÓDULOS DE NEGOCIO (Nebula)
├── accounting # Bounded Context: Contabilidad
│ ├── accounting.routes.ts
│ ├── components # Smart Components
│ ├── services # AccountingService (Lógica)
│ └── models # Interfaces locales
├── payroll # Bounded Context: Nómina
└── treasury # Bounded Context: Tesorería
Es el único que inyecta servicios.
@Component({
standalone: true,
imports: [TableComponent, AsyncPipe],
template: `<app-table
[data]="invoices()"
(edit)="onEdit($event)"
></app-table>`,
})
export class InvoiceListComponent {
private service = inject(InvoiceService);
// SIGNAL: Estado reactivo
invoices = this.service.invoicesSignal;
onEdit(id: string) {
this.service.openDraft(id);
}
}
Maneja la comunicación y el estado.
@Injectable({ providedIn: "root" })
export class InvoiceService {
private http = inject(HttpClient);
// State: Signal privado, expuesto como ReadOnly
private _invoices = signal<Invoice[]>([]);
public invoicesSignal = this._invoices.asReadonly();
loadPending() {
this.http
.get<Invoice[]>("/api/v1/invoices")
.subscribe((data) => this._invoices.set(data));
}
}
Explicación del Flujo:
loadPending()_invoices.set(data)invoicesSignal() (reactivo)@Input() a Presentational Component@Output() (ej. edit)Principios Clave:
| Responsabilidad | Smart Component | Service | Presentational Component |
|---|---|---|---|
| HTTP calls | ❌ NO | ✅ SÍ | ❌ NO |
| State management | ❌ NO (solo lee) | ✅ SÍ (Signals) | ❌ NO |
| Business logic | ❌ NO | ✅ SÍ | ❌ NO |
| Display data | ✅ SÍ | ❌ NO | ✅ SÍ |
| Emit events | ❌ NO | ❌ NO | ✅ SÍ |
| Dependency injection | ✅ SÍ (Services) | N/A | ❌ NO |
Cuándo usar Signals vs RxJS:
CentricaModel) debe tener su interfaz TypeScript exacta en features/{modulo}/models.
CentricaModel esté mergeado y publicado.any. Usar unknown si es estrictamente necesario, pero preferir interfaces tipadas.changeDetection: ChangeDetectionStrategy.OnPush.features deben cargarse perezosamente (loadComponent / loadChildren).NOTA: Este patrón busca que el cambio de desarrollador sea indoloro. Si sabes Angular y lees esto, sabes dónde está todo.
| Version | Fecha | Autor | Descripcion |
|---|---|---|---|
| 1.1.0 | 2026-03-04 | Carlos Torres | Revision, sanitizacion y publicacion en Wiki Arquitectura Centrica. |
| 1.0.0 | 2025-12-27 | Carlos Torres | Creacion del documento. |