angular-frontend-clean-architecture
npx skills add https://github.com/luismpenholato/maurao-skills --skill angular-frontend-clean-architecture
Agent 安装分布
Skill 文档
Frontend Angular â Clean Architecture + Standalone
Guia para criar e manter frontends Angular com estrutura por features (vertical slice), componentes standalone, signals e ng-zorro-antd.
Quando usar esta skill
- Adicionar nova página/feature (nova pasta em
pages/com listagem, formulário, service, modelos). - Criar componente reutilizável em
shared/components/, diretiva emshared/directives/, pipe emshared/pipes/. - Adicionar service (HTTP, estado global), guard, interceptor.
- Definir ou alterar rotas em
app.routes.ts. - Revisar ou refatorar código para seguir a estrutura e convenções do boilerplate.
Estrutura do projeto
frontend/src/app/
âââ app.ts # Bootstrap, providers (HTTP, interceptors)
âââ app.config.ts # provideRouter, provideHttpClient, etc.
âââ app.routes.ts # Rotas (guards quando necessário)
âââ layout/ # Layout principal (header, drawer, outlet)
â âââ main-layout/
âââ pages/ # Features por domÃnio (vertical slice)
â âââ products/
â âââ product.model.ts
â âââ product.service.ts
â âââ products-list/ # Uma tela = uma pasta com tudo junto
â âââ products-list.component.ts
â âââ products-list.component.html
â âââ products-list.component.scss
â âââ products-list.component.spec.ts
âââ shared/
â âââ components/ # Componentes reutilizáveis (page-header, loading, etc.)
â âââ directives/ # Diretivas (autofocus, currency-mask, etc.)
â âââ pipes/
â âââ services/ # Serviços globais (loading, layout)
â âââ guards/
â âââ interceptors/
â âââ utils/
âââ environments/ # environment.apiBaseUrl, etc.
Regra: pages/ contém uma pasta por domÃnio (ex.: products). Dentro da feature ficam o modelo, o service e uma pasta por tela (cada tela com component, html, scss e spec juntos). Nem toda feature tem listagem ou formulário â cria-se só as telas que existirem. shared/ contém apenas o que é reutilizado entre páginas.
Checklist â Nova feature (ex.: Orders)
Use este checklist e crie os itens na ordem indicada.
Modelo e service
-
pages/orders/order.model.ts: interfaces (ex.:Order,OrderCreateRequest). -
pages/orders/order.service.ts:@Injectable({ providedIn: 'root' }),inject(HttpClient), métodos que retornamObservable<T>(list, getById, create, update, delete). Usarenvironment.apiBaseUrlpara base da API.
Telas da feature (cada uma em sua pasta, tudo junto)
- Uma pasta por tela em
pages/orders/(ex.:orders-list/), com*.component.ts,*.component.html,*.component.scss,*.component.spec.tsna mesma pasta. - Componente:
ChangeDetectionStrategy.OnPush,host: { class: 'app-orders-list' },inject(OrderService), signals/computed conforme a tela. Template:@if/@for,[class.x]ou[style.x],track item.idno@for. - Se a tela for formulário: form reativo,
FormBuilder, validações; helper opcional (validação/build request) na mesma pasta; diretivas compartilhadas (ex.:appCurrencyMask) quando aplicável.
Rotas
- Em
app.routes.ts: uma rota por tela que existir na feature, comcanActivate: [authGuard]quando necessário.
Shared (somente se reutilizável)
- Componente/diretiva/pipe em
shared/apenas quando usado em mais de uma feature ou quando for UI genérica (ex.: page-header, loading).
Padrões de código
Componente standalone (sem standalone: true â é padrão no Angular 21)
import { ChangeDetectionStrategy, Component, inject, input, signal } from '@angular/core';
@Component({
selector: 'app-page-header',
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'app-page-header' },
imports: [RouterLink, NzBreadCrumbModule],
templateUrl: './page-header.component.html',
styleUrl: './page-header.component.scss'
})
export class PageHeaderComponent {
title = input.required<string>();
subtitle = input<string>();
breadcrumb = input<BreadcrumbItem[]>([]);
}
Service com HttpClient
@Injectable({ providedIn: 'root' })
export class ProductService {
private readonly http = inject(HttpClient);
private readonly baseUrl = `${environment.apiBaseUrl}/api/products`;
list(): Observable<Product[]> {
return this.http.get<Product[]>(this.baseUrl);
}
}
Template â controle de fluxo e bindings
@if (loading()) {
<nz-spin nzSimple></nz-spin>
} @else {
@for (item of items(); track item.id) {
<div [class.active]="item.isActive">{{ item.name }}</div>
}
}
Diretiva com signal input e host
@Directive({
selector: '[appAutofocus]',
host: {
'(focus)': 'onFocus($event)'
}
})
export class AutofocusDirective {
readonly appAutofocus = input(true, { transform: booleanAttribute });
}
Convenções
- Componentes: OnPush,
host: { class: 'app-<nome>' }, signalinput()/output()quando fizer sentido; evitar@Input()/@Output()em código novo. - Templates:
@if,@for,@switch;track item.id(ou estável) no@for; semngClass/ngStyle. - Serviços:
inject()em vez de constructor injection;providedIn: 'root'para serviços globais. - Rotas: um arquivo
app.routes.ts; guards emshared/guards/, importados nas rotas. - Nomes: kebab-case para pastas e arquivos; prefixo
apppara seletores de componentes/diretivas do app.
Tratamento de erros e loading
- Chamadas HTTP: usar
catchError,finalize,timeoutnos subscribes; mensagens viaNzMessageServicequando fizer sentido. - Loading: signal
loadingno componente;[nzLoading]="loading()"ou overlay compartilhado viaLoadingServicequando for global.
Recursos adicionais
- Estrutura detalhada e fluxo de dados: reference.md.