Angular frontend clean architecture
Skill luismpenholato/maurao-skills/skills/angular-frontend-clean-architecture
Angular 21 standalone frontend with Clean Architecture, vertical slice (pages by feature), signals, OnPush, and ng-zorro. Use when creating or refactoring Angular apps, adding pages, components, services, directives, pipes, or when the user mentions Angular frontend, standalone components, or signals.From its SKILL.md
npx -y skills add luismpenholato/maurao-skills --skill angular-frontend-clean-architectureAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
6.3 KB, ~1.5k tokens by cl100k_base, as published. Nobody here has run it
Frontend Angular – Clean Architecture + Standalone
Guide for creating and maintaining Angular frontends with features structure (vertical slice), standalone components, signals, and ng-zorro-antd.
When to use
- Add a new page/feature (new folder in
pages/with listing, form, service, models). - Create component in
shared/components/, directive inshared/directives/, pipe inshared/pipes/. - Add service (HTTP, global state), guard, interceptor.
- Define or change routes in
app.routes.ts. - Review or refactor code to follow this skill's pattern.
When not to use
- AngularJS or legacy non-Angular projects.
- Codebases built on legacy NgModules without standalone components.
- Applications that use another design system as the primary UI kit (e.g., Angular Material).
- Library-only projects without routed pages or feature screens.
Target stack
| Technology | Usage |
|---|---|
| Angular 21 | Standalone, signals, @if / @for |
| ng-zorro-antd 21 | UI (tables, forms, layout) |
| RxJS 7 | HTTP and streams |
| TypeScript 5.9 | Typing |
| Vitest 4 | Tests via ng test |
This skill uses ng-zorro-antd as the default design system, matching CleanStack. Do not force ng-zorro on projects that already use Angular Material or another UI kit — adapt the patterns while keeping the feature structure.
Project structure
src/
├── app/
│ ├── app.ts # Root (layout + overlays)
│ ├── app.config.ts # provideRouter, provideHttpClient, …
│ ├── app.routes.ts # Routes and guards
│ ├── layout/
│ │ └── main-layout/
│ ├── pages/ # Features (vertical slice)
│ │ └── products/
│ │ ├── product.model.ts
│ │ ├── product.service.ts
│ │ ├── products-list/
│ │ └── product-form/
│ └── shared/
│ ├── components/ # page-header, loading, …
│ ├── directives/ # autofocus, currency-mask, …
│ ├── guards/ # authGuard (CanActivateFn)
│ ├── interceptors/
│ ├── pipes/
│ ├── services/ # loading, layout, confirmation
│ └── utils/
├── environments/ # apiBaseUrl per environment
└── styles/ # _tokens.scss, _ng-zorro-overrides.scss
Rule: pages/ = one folder per domain; inside it model, service, and one subfolder per screen. shared/ = only what is reusable across features.
Checklist – New feature (e.g., Orders)
Model and service
-
pages/orders/order.model.ts: interfaces (Order,OrderCreateRequest, …). -
pages/orders/order.service.ts:@Injectable({ providedIn: 'root' }),inject(HttpClient),Observablemethods. Base:`${environment.apiBaseUrl}/api/orders`.
Screens
- One folder per screen (
orders-list/,order-form/) with*.component.ts/html/scss/spec. -
ChangeDetectionStrategy.OnPush,host: { class: 'app-orders-list' }, signals/computed. - Template:
@if/@forwithtrack; nongClass/ngStyle.
Routes
-
app.routes.ts: feature routes;canActivate: [authGuard]when needed.
Shared (only if reusable)
- Component/directive/pipe in
shared/only when used in more than one feature.
Code patterns
Standalone component (Angular 21 pattern — no standalone: true)
@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>();
}
Service with 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);
}
}
Guard
export const authGuard: CanActivateFn = () => true; // replace with real auth
Conventions
- Components: OnPush,
host: { class: 'app-<name>' },input()/output()with signals. - Templates:
@if,@for,@switch; stabletrackin@for. - Services:
inject();providedIn: 'root'for globals. - Routes:
app.routes.ts; guards inshared/guards/. UI path segments in English (products,new,edit); API at/api/products. - Environment:
src/environments/— never hardcode API URL in components. - Theme:
src/styles/_tokens.scss+_ng-zorro-overrides.scss; toggle viaLayoutService(body.theme-dark). - Drawer/menu:
nzWrapClassName="app-drawer",*nzDrawerContent, CSS.app-drawer .drawer-menu(portaled to body). - SEO:
title+data.descriptionon routes;AppTitleStrategy;noindexinindex.html(admin app). - Names: kebab-case in folders/files;
appprefix on selectors.
Error handling and loading
- HTTP:
catchError,finalize,timeout; feedback viaNzMessageService. - Loading: signal in component or
LoadingService/ global overlay inshared/services/. - Global errors: interceptor in
shared/interceptors/.
Anti-patterns
- Business logic in
app.routes.tsinstead of page components or services. - Hardcoded API URLs instead of
environment.apiBaseUrl. - Using
@Input()/@Output()in new standalone components instead ofinput()/output(). - Placing entire features in
shared/instead ofpages/. - Using
ngClass/ngStylewhen[class.x]/[style.x]suffices.
Additional resources
- Detailed structure and data flow: reference.md.
What ships with it: 1 file
3.6 KB alongside SKILL.md
- reference.md3.6 KB