Professional Workflow: Angular Project with Cursor from Setup to Deploy
You have learned about Cursor, its rules system, Agent Mode, Plan Mode, Hooks, and the MCP protocol. Now it is time to bring everything together into a real professional workflow. This final article of the series is an operational case study: we will build a complete Angular project using Cursor as an AI co-pilot at every stage, from project initialization all the way through production deployment.
This is not an abstract collection of best practices. Every section shows real commands, effective prompts, concrete configurations, and the decisions a professional team makes when integrating Cursor into their daily development process. By the end of this article you will have a complete, replicable playbook for any Angular project.
The project we will build is a task management dashboard with Angular 19, SSR, signals, standalone components, automated testing, and CI/CD with GitHub Actions. This represents the kind of real-world complexity you encounter in professional work every day.
What You Will Learn in This Article
- How to structure an optimal
.cursor/rules/setup for Angular projects - Project setup with Agent Mode: from zero to full structure in minutes
- Generating standalone components with signals and reactive forms guided by AI
- SSR and incremental hydration configuration with Cursor as your assistant
- Testing workflow: unit tests with Jest/Vitest and E2E with Playwright, written with AI
- Intelligent refactoring of legacy patterns with Agent Mode
- AI-assisted performance optimization: lazy loading, bundle analysis, Core Web Vitals
- Complete CI/CD pipeline generated with Cursor for GitHub Actions and Firebase
- End-to-end case study: a complete feature from idea to production deploy
- Exclusive tips and tricks for Angular developers using Cursor every day
Technical Requirements
- Node.js 22+ and Angular CLI 19+
- Cursor IDE (Pro plan recommended for unlimited Agent Mode)
- Git and a GitHub account for CI/CD
- Basic knowledge of Angular, TypeScript, and RxJS
- Optional: Firebase account for deployment, familiarity with SSR
Phase 1 - Configuring Cursor Rules for an Angular Project
The first step toward a professional workflow is configuring Cursor so it knows your project conventions before you write the first line of code. A well-structured rules file transforms Cursor from a generic assistant into a specialist collaborator trained in your Angular stack.
With Cursor 0.45+, rules live in the .cursor/rules/ directory as
.mdc files. You can have global rules that are always active and context-specific
rules that activate based on file patterns. For a professional Angular project, I recommend
this structure:
# Rules directory structure
.cursor/
rules/
angular-core.mdc # Always-active fundamental rules
angular-components.mdc # Standalone component rules
angular-testing.mdc # Test writing rules
angular-performance.mdc # Performance optimization rules
angular-ssr.mdc # SSR and hydration rules
Here is the complete content of angular-core.mdc, the most important rule that
establishes the architectural foundation of the project:
---
description: Core rules for Angular 19+ projects with standalone components and signals
globs: ["**/*.ts", "**/*.html"]
alwaysApply: true
---
# Angular Core Rules
## Architecture and Structure
- ALWAYS use standalone components (no NgModules except in exceptional cases)
- Organize by feature/domain, not by type (no global "components/", "services/" folders)
- Feature directory structure: `src/app/features/[feature-name]/`
- Each feature has: components/, services/, models/, guards/ (if needed)
- Shared components in `src/app/shared/`
- Core singleton services in `src/app/core/`
## TypeScript and Dependency Injection
- ALWAYS use `inject()` for dependency injection (not constructor injection)
- TypeScript strict mode mandatory
- Avoid `any` - use `unknown` with type narrowing when necessary
- Use `readonly` for properties that do not change after initialization
- Interface over Type for defining object shapes
## State Management with Signals
- Use signals for all local component state
- `computed()` for derived values, never getters that call functions
- `effect()` only for side effects (DOM, non-reactive API calls, logging)
- For state shared across components: service with signals exposed as readonly
- RxJS for complex async operations (HTTP, WebSocket), then `toSignal()` to expose in templates
## Templates and Rendering
- ALWAYS use the new control flow syntax: @if, @for, @switch (not *ngIf, *ngFor)
- `@for` always requires a `track` expression - use unique IDs, not index
- ChangeDetectionStrategy.OnPush for ALL components (performance default)
- NgOptimizedImage for all images (src → ngSrc)
## Naming Conventions
- Files: kebab-case (`user-profile.component.ts`)
- Classes: PascalCase (`UserProfileComponent`)
- Signals: no prefix/suffix, no `
09 - Professional Workflow: Angular Project with Cursor from Setup to Deploy | Federico Calò
09 - Professional Workflow: Angular Project with Cursor from Setup to Deploy | Federico Calò
Salta al contenuto principaleCiao! Sono
Federico Calò
Sviluppatore Software | Divulgatore Tecnico
Creo applicazioni web moderne e strumenti digitali personalizzati per aiutare le attività a crescere attraverso l'innovazione tecnologica. La mia passione è unire informatica ed economia per generare valore reale.
Chi Sono
La mia passione per l'informatica è nata tra i banchi dell'Istituto Tecnico Commerciale di Maglie, dove ho scoperto il potere della programmazione e il fascino di creare soluzioni digitali. Fin da subito, ho capito che l'informatica non era solo codice, ma uno strumento straordinario per trasformare idee in realtà.
Durante gli studi superiori in Sistemi Informativi Aziendali, ho iniziato a intrecciare informatica ed economia, comprendendo come la tecnologia possa essere il motore della crescita per qualsiasi attività. Questa visione mi ha accompagnato all'Università degli Studi di Bari, dove ho conseguito la Laurea in Informatica, approfondendo le mie competenze tecniche e la mia passione per lo sviluppo software.
Oggi metto questa esperienza al servizio di imprese, professionisti e startup, creando soluzioni digitali su misura che automatizzano processi, ottimizzano risorse e aprono nuove opportunità di business. Perché la vera innovazione inizia quando la tecnologia incontra le esigenze reali delle persone.
Le Mie Competenze
Analisi Dati & Modelli Previsionali
Trasformo i dati in insights strategici con analisi approfondite e modelli predittivi per decisioni informate
Automazione Processi
Creo strumenti personalizzati che automatizzano operazioni ripetitive e liberano tempo per attività a valore aggiunto
Sistemi Custom
Sviluppo sistemi software su misura, dalle integrazioni tra piattaforme alle dashboard personalizzate
const federico = {
nome: "Federico Calò",
ruolo: "Sviluppatore Software",
città: "Bari, Italia",
missione: "Aiutare attraverso l'informatica",
passioni: [
"Codice Pulito",
"Innovazione",
"Crescita Continua"
]
};
La Mia Missione
Credo fermamente che l'informatica sia lo strumento più potente per trasformare le idee in realtà e migliorare la vita delle persone.
Democratizzare la Tecnologia
La mia missione è rendere l'informatica accessibile a tutti: dalle piccole imprese locali alle startup innovative, fino ai professionisti che vogliono digitalizzare la propria attività. Ogni realtà merita di sfruttare le potenzialità del digitale.
Unire Informatica ed Economia
Non è solo questione di scrivere codice: è capire come la tecnologia possa generare valore reale. Intrecciando competenze informatiche e visione economica, aiuto le attività a crescere, ottimizzare processi e raggiungere nuovi traguardi di efficienza e redditività.
Creare Soluzioni su Misura
Ogni attività è unica, e così devono esserlo le soluzioni. Sviluppo strumenti personalizzati che rispondono alle esigenze specifiche di ciascun cliente, automatizzando processi ripetitivi e liberando tempo per ciò che conta davvero: far crescere il business.
Trasforma la Tua Attività con la Tecnologia
Che tu gestisca un negozio, uno studio professionale o un'azienda, posso aiutarti a sfruttare le potenzialità dell'informatica per lavorare meglio, più velocemente e in modo più intelligente.
Parliamone Insieme →Formazione & Competenze
Il mio percorso accademico e le tecnologie che padroneggio
Certificazioni Professionali
8 certificazioni conseguite
💻 Linguaggi & Tecnologie
☕Java🐍Python📜JavaScript🅰️Angular⚛️React🔷TypeScript🗄️SQL🐘PHP🎨CSS/SCSS🔧Node.js🐳Docker🌿GitContattami
Hai un progetto in mente? Parliamone! Compila il form qui sotto e ti risponderò al più presto.
* Campi obbligatori. I tuoi dati saranno utilizzati solo per rispondere alla tua richiesta.
suffix (`users`, not `users
09 - Professional Workflow: Angular Project with Cursor from Setup to Deploy | Federico Calò
09 - Professional Workflow: Angular Project with Cursor from Setup to Deploy | Federico Calò
Salta al contenuto principaleCiao! Sono
Federico Calò
Sviluppatore Software | Divulgatore Tecnico
Creo applicazioni web moderne e strumenti digitali personalizzati per aiutare le attività a crescere attraverso l'innovazione tecnologica. La mia passione è unire informatica ed economia per generare valore reale.
Chi Sono
La mia passione per l'informatica è nata tra i banchi dell'Istituto Tecnico Commerciale di Maglie, dove ho scoperto il potere della programmazione e il fascino di creare soluzioni digitali. Fin da subito, ho capito che l'informatica non era solo codice, ma uno strumento straordinario per trasformare idee in realtà.
Durante gli studi superiori in Sistemi Informativi Aziendali, ho iniziato a intrecciare informatica ed economia, comprendendo come la tecnologia possa essere il motore della crescita per qualsiasi attività. Questa visione mi ha accompagnato all'Università degli Studi di Bari, dove ho conseguito la Laurea in Informatica, approfondendo le mie competenze tecniche e la mia passione per lo sviluppo software.
Oggi metto questa esperienza al servizio di imprese, professionisti e startup, creando soluzioni digitali su misura che automatizzano processi, ottimizzano risorse e aprono nuove opportunità di business. Perché la vera innovazione inizia quando la tecnologia incontra le esigenze reali delle persone.
Le Mie Competenze
Analisi Dati & Modelli Previsionali
Trasformo i dati in insights strategici con analisi approfondite e modelli predittivi per decisioni informate
Automazione Processi
Creo strumenti personalizzati che automatizzano operazioni ripetitive e liberano tempo per attività a valore aggiunto
Sistemi Custom
Sviluppo sistemi software su misura, dalle integrazioni tra piattaforme alle dashboard personalizzate
const federico = {
nome: "Federico Calò",
ruolo: "Sviluppatore Software",
città: "Bari, Italia",
missione: "Aiutare attraverso l'informatica",
passioni: [
"Codice Pulito",
"Innovazione",
"Crescita Continua"
]
};
La Mia Missione
Credo fermamente che l'informatica sia lo strumento più potente per trasformare le idee in realtà e migliorare la vita delle persone.
Democratizzare la Tecnologia
La mia missione è rendere l'informatica accessibile a tutti: dalle piccole imprese locali alle startup innovative, fino ai professionisti che vogliono digitalizzare la propria attività. Ogni realtà merita di sfruttare le potenzialità del digitale.
Unire Informatica ed Economia
Non è solo questione di scrivere codice: è capire come la tecnologia possa generare valore reale. Intrecciando competenze informatiche e visione economica, aiuto le attività a crescere, ottimizzare processi e raggiungere nuovi traguardi di efficienza e redditività.
Creare Soluzioni su Misura
Ogni attività è unica, e così devono esserlo le soluzioni. Sviluppo strumenti personalizzati che rispondono alle esigenze specifiche di ciascun cliente, automatizzando processi ripetitivi e liberando tempo per ciò che conta davvero: far crescere il business.
Trasforma la Tua Attività con la Tecnologia
Che tu gestisca un negozio, uno studio professionale o un'azienda, posso aiutarti a sfruttare le potenzialità dell'informatica per lavorare meglio, più velocemente e in modo più intelligente.
Parliamone Insieme →Formazione & Competenze
Il mio percorso accademico e le tecnologie che padroneggio
Certificazioni Professionali
8 certificazioni conseguite
💻 Linguaggi & Tecnologie
☕Java🐍Python📜JavaScript🅰️Angular⚛️React🔷TypeScript🗄️SQL🐘PHP🎨CSS/SCSS🔧Node.js🐳Docker🌿GitContattami
Hai un progetto in mente? Parliamone! Compila il form qui sotto e ti risponderò al più presto.
* Campi obbligatori. I tuoi dati saranno utilizzati solo per rispondere alla tua richiesta.
or `usersSignal`)
- Observables: `
09 - Professional Workflow: Angular Project with Cursor from Setup to Deploy | Federico Calò
09 - Professional Workflow: Angular Project with Cursor from Setup to Deploy | Federico Calò
Salta al contenuto principaleCiao! Sono
Federico Calò
Sviluppatore Software | Divulgatore Tecnico
Creo applicazioni web moderne e strumenti digitali personalizzati per aiutare le attività a crescere attraverso l'innovazione tecnologica. La mia passione è unire informatica ed economia per generare valore reale.
Chi Sono
La mia passione per l'informatica è nata tra i banchi dell'Istituto Tecnico Commerciale di Maglie, dove ho scoperto il potere della programmazione e il fascino di creare soluzioni digitali. Fin da subito, ho capito che l'informatica non era solo codice, ma uno strumento straordinario per trasformare idee in realtà.
Durante gli studi superiori in Sistemi Informativi Aziendali, ho iniziato a intrecciare informatica ed economia, comprendendo come la tecnologia possa essere il motore della crescita per qualsiasi attività. Questa visione mi ha accompagnato all'Università degli Studi di Bari, dove ho conseguito la Laurea in Informatica, approfondendo le mie competenze tecniche e la mia passione per lo sviluppo software.
Oggi metto questa esperienza al servizio di imprese, professionisti e startup, creando soluzioni digitali su misura che automatizzano processi, ottimizzano risorse e aprono nuove opportunità di business. Perché la vera innovazione inizia quando la tecnologia incontra le esigenze reali delle persone.
Le Mie Competenze
Analisi Dati & Modelli Previsionali
Trasformo i dati in insights strategici con analisi approfondite e modelli predittivi per decisioni informate
Automazione Processi
Creo strumenti personalizzati che automatizzano operazioni ripetitive e liberano tempo per attività a valore aggiunto
Sistemi Custom
Sviluppo sistemi software su misura, dalle integrazioni tra piattaforme alle dashboard personalizzate
const federico = {
nome: "Federico Calò",
ruolo: "Sviluppatore Software",
città: "Bari, Italia",
missione: "Aiutare attraverso l'informatica",
passioni: [
"Codice Pulito",
"Innovazione",
"Crescita Continua"
]
};
La Mia Missione
Credo fermamente che l'informatica sia lo strumento più potente per trasformare le idee in realtà e migliorare la vita delle persone.
Democratizzare la Tecnologia
La mia missione è rendere l'informatica accessibile a tutti: dalle piccole imprese locali alle startup innovative, fino ai professionisti che vogliono digitalizzare la propria attività. Ogni realtà merita di sfruttare le potenzialità del digitale.
Unire Informatica ed Economia
Non è solo questione di scrivere codice: è capire come la tecnologia possa generare valore reale. Intrecciando competenze informatiche e visione economica, aiuto le attività a crescere, ottimizzare processi e raggiungere nuovi traguardi di efficienza e redditività.
Creare Soluzioni su Misura
Ogni attività è unica, e così devono esserlo le soluzioni. Sviluppo strumenti personalizzati che rispondono alle esigenze specifiche di ciascun cliente, automatizzando processi ripetitivi e liberando tempo per ciò che conta davvero: far crescere il business.
Trasforma la Tua Attività con la Tecnologia
Che tu gestisca un negozio, uno studio professionale o un'azienda, posso aiutarti a sfruttare le potenzialità dell'informatica per lavorare meglio, più velocemente e in modo più intelligente.
Parliamone Insieme →Formazione & Competenze
Il mio percorso accademico e le tecnologie che padroneggio
Certificazioni Professionali
8 certificazioni conseguite
💻 Linguaggi & Tecnologie
☕Java🐍Python📜JavaScript🅰️Angular⚛️React🔷TypeScript🗄️SQL🐘PHP🎨CSS/SCSS🔧Node.js🐳Docker🌿GitContattami
Hai un progetto in mente? Parliamone! Compila il form qui sotto e ti risponderò al più presto.
* Campi obbligatori. I tuoi dati saranno utilizzati solo per rispondere alla tua richiesta.
suffix (`users
09 - Professional Workflow: Angular Project with Cursor from Setup to Deploy | Federico Calò
09 - Professional Workflow: Angular Project with Cursor from Setup to Deploy | Federico Calò
Salta al contenuto principaleCiao! Sono
Federico Calò
Sviluppatore Software | Divulgatore Tecnico
Creo applicazioni web moderne e strumenti digitali personalizzati per aiutare le attività a crescere attraverso l'innovazione tecnologica. La mia passione è unire informatica ed economia per generare valore reale.
Chi Sono
La mia passione per l'informatica è nata tra i banchi dell'Istituto Tecnico Commerciale di Maglie, dove ho scoperto il potere della programmazione e il fascino di creare soluzioni digitali. Fin da subito, ho capito che l'informatica non era solo codice, ma uno strumento straordinario per trasformare idee in realtà.
Durante gli studi superiori in Sistemi Informativi Aziendali, ho iniziato a intrecciare informatica ed economia, comprendendo come la tecnologia possa essere il motore della crescita per qualsiasi attività. Questa visione mi ha accompagnato all'Università degli Studi di Bari, dove ho conseguito la Laurea in Informatica, approfondendo le mie competenze tecniche e la mia passione per lo sviluppo software.
Oggi metto questa esperienza al servizio di imprese, professionisti e startup, creando soluzioni digitali su misura che automatizzano processi, ottimizzano risorse e aprono nuove opportunità di business. Perché la vera innovazione inizia quando la tecnologia incontra le esigenze reali delle persone.
Le Mie Competenze
Analisi Dati & Modelli Previsionali
Trasformo i dati in insights strategici con analisi approfondite e modelli predittivi per decisioni informate
Automazione Processi
Creo strumenti personalizzati che automatizzano operazioni ripetitive e liberano tempo per attività a valore aggiunto
Sistemi Custom
Sviluppo sistemi software su misura, dalle integrazioni tra piattaforme alle dashboard personalizzate
const federico = {
nome: "Federico Calò",
ruolo: "Sviluppatore Software",
città: "Bari, Italia",
missione: "Aiutare attraverso l'informatica",
passioni: [
"Codice Pulito",
"Innovazione",
"Crescita Continua"
]
};
La Mia Missione
Credo fermamente che l'informatica sia lo strumento più potente per trasformare le idee in realtà e migliorare la vita delle persone.
Democratizzare la Tecnologia
La mia missione è rendere l'informatica accessibile a tutti: dalle piccole imprese locali alle startup innovative, fino ai professionisti che vogliono digitalizzare la propria attività. Ogni realtà merita di sfruttare le potenzialità del digitale.
Unire Informatica ed Economia
Non è solo questione di scrivere codice: è capire come la tecnologia possa generare valore reale. Intrecciando competenze informatiche e visione economica, aiuto le attività a crescere, ottimizzare processi e raggiungere nuovi traguardi di efficienza e redditività.
Creare Soluzioni su Misura
Ogni attività è unica, e così devono esserlo le soluzioni. Sviluppo strumenti personalizzati che rispondono alle esigenze specifiche di ciascun cliente, automatizzando processi ripetitivi e liberando tempo per ciò che conta davvero: far crescere il business.
Trasforma la Tua Attività con la Tecnologia
Che tu gestisca un negozio, uno studio professionale o un'azienda, posso aiutarti a sfruttare le potenzialità dell'informatica per lavorare meglio, più velocemente e in modo più intelligente.
Parliamone Insieme →Formazione & Competenze
Il mio percorso accademico e le tecnologie che padroneggio
Certificazioni Professionali
8 certificazioni conseguite
💻 Linguaggi & Tecnologie
☕Java🐍Python📜JavaScript🅰️Angular⚛️React🔷TypeScript🗄️SQL🐘PHP🎨CSS/SCSS🔧Node.js🐳Docker🌿GitContattami
Hai un progetto in mente? Parliamone! Compila il form qui sotto e ti risponderò al più presto.
* Campi obbligatori. I tuoi dati saranno utilizzati solo per rispondere alla tua richiesta.
)
- Private methods: `_` prefix when clarity is needed
## Forms
- Reactive Forms (ReactiveFormsModule) for all non-trivial forms
- Template-driven only for forms with 1-2 fields and no complex validation
- Typed forms mandatory (`FormControl<string>`, not `FormControl`)
- Custom validators as pure functions (not classes)
This rule gives Cursor complete architectural context. When you ask it to generate a
component, service, or feature, Cursor automatically knows to use inject(),
signals, and the new control flow syntax. You do not need to repeat that in every prompt.
Common Mistake: Rules That Are Too Generic
Many teams create a single huge .cursorrules file with hundreds of lines.
The result is that Cursor cannot prioritize the most relevant instructions for the current
context. Use separate files with specific glob patterns: a component rule activates only
on *.component.ts, keeping context focused and responses more precise.
Phase 2 - Project Setup with Agent Mode
With rules configured, it is time to create the project. Instead of manually running every command and creating every file, we use Agent Mode to delegate the entire bootstrap phase. This is one of Cursor's most powerful use cases: give high-level instructions and let the agent handle all the operational steps.
Open Cursor, create a new folder for the project, and launch Agent Mode with Cmd+Shift+I (or Ctrl+Shift+I on Windows/Linux). Then use this prompt:
Agent Mode Prompt: Project Bootstrap
Create a new Angular 19 project called "task-dashboard" with these features:
1. Angular CLI with SSR enabled (--ssr flag)
2. TypeScript strict mode
3. Jest instead of Karma for unit tests (configure jest.config.ts)
4. ESLint with angular-eslint
5. Prettier configured with .prettierrc
6. Feature-based structure:
- src/app/core/ (interceptors, guards, singleton services)
- src/app/shared/ (shared components and pipes)
- src/app/features/tasks/ (main feature)
- src/app/features/auth/ (authentication)
7. Development environment with proxy to http://localhost:3000 (backend API)
8. Git initialized with appropriate .gitignore
Run the necessary commands, install dependencies, and show me the final structure.
Generating the Tasks Feature with Agent Mode
Agent Mode Prompt: Complete Tasks Feature
Create the complete "tasks" feature in src/app/features/tasks/ following .cursor/rules/:
DATA MODEL (src/app/features/tasks/models/task.model.ts):
- Task interface: id (string), title (string), description (string),
status ('todo' | 'in-progress' | 'done'), priority ('low' | 'medium' | 'high'),
createdAt (Date), dueDate (Date | null), assigneeId (string | null)
- TaskStatus and TaskPriority types (union types)
- CreateTaskRequest and UpdateTaskRequest interfaces (Partial<Task> without id/createdAt)
SERVICE (src/app/features/tasks/services/task.service.ts):
- Use inject(HttpClient)
- Signals: tasks = signal<Task[]>([]), loading = signal(false), error = signal<string | null>(null)
- Computed: completedTasks, pendingTasks, tasksByPriority
- Methods: loadTasks(), createTask(), updateTask(), deleteTask(), updateStatus()
- All methods update signals after HTTP calls
STANDALONE COMPONENTS:
1. TaskListComponent - task list with status/priority filters
2. TaskCardComponent - single task card with actions
3. TaskFormComponent - create/edit form with typed reactive forms
4. TaskDetailComponent - detail view with routing
ROUTING: configure lazy-loaded routing in tasks.routes.ts
ALWAYS follow: standalone: true, inject(), signals, ChangeDetectionStrategy.OnPush,
@if/@for syntax, TypeScript strict mode.
Phase 3 - Components with Signals and Reactive Forms
Let us look in detail at how Cursor generates modern Angular components. Here is the
TaskFormComponent output and how the signals pattern looks in practice:
// task-form.component.ts - Generated by Cursor with Agent Mode
import { Component, ChangeDetectionStrategy, inject, input, output } from '@angular/core';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
import { CreateTaskRequest, TaskPriority } from '../models/task.model';
import { TaskService } from '../services/task.service';
@Component({
selector: 'app-task-form',
standalone: true,
imports: [ReactiveFormsModule],
templateUrl: './task-form.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class TaskFormComponent {
// Dependency injection with inject()
private readonly fb = inject(FormBuilder);
private readonly taskService = inject(TaskService);
// Signal-based inputs (Angular 17+ API)
readonly initialData = input<Partial<CreateTaskRequest> | null>(null);
readonly isEdit = input(false);
// Signal-based outputs
readonly formSubmit = output<CreateTaskRequest>();
readonly formCancel = output<void>();
// Typed reactive form
readonly form = this.fb.group({
title: this.fb.control('', {
validators: [Validators.required, Validators.minLength(3), Validators.maxLength(100)],
nonNullable: true
}),
description: this.fb.control('', { nonNullable: true }),
priority: this.fb.control<TaskPriority>('medium', { nonNullable: true }),
dueDate: this.fb.control<string | null>(null)
});
// Loading state from service (readonly - consumers cannot mutate)
readonly loading = this.taskService.loading;
onSubmit(): void {
if (this.form.invalid) return;
const value = this.form.getRawValue();
this.formSubmit.emit({
title: value.title,
description: value.description,
priority: value.priority,
dueDate: value.dueDate ? new Date(value.dueDate) : null,
assigneeId: null
});
}
onCancel(): void {
this.form.reset();
this.formCancel.emit();
}
}
TaskService with Signals: Complete Reactive Pattern
// task.service.ts - Signals pattern for feature-wide state
import { Injectable, inject, signal, computed } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Task, CreateTaskRequest, TaskStatus } from '../models/task.model';
import { tap, catchError, EMPTY, finalize } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class TaskService {
private readonly http = inject(HttpClient);
// Private writable signals (internal state)
private readonly _tasks = signal<Task[]>([]);
private readonly _loading = signal(false);
private readonly _error = signal<string | null>(null);
// Public readonly signals (consumers cannot mutate)
readonly tasks = this._tasks.asReadonly();
readonly loading = this._loading.asReadonly();
readonly error = this._error.asReadonly();
// Computed signals - derived from state
readonly completedTasks = computed(() =>
this._tasks().filter(t => t.status === 'done')
);
readonly pendingTasks = computed(() =>
this._tasks().filter(t => t.status !== 'done')
);
readonly completionRate = computed(() => {
const total = this._tasks().length;
if (total === 0) return 0;
return Math.round((this.completedTasks().length / total) * 100);
});
loadTasks(): void {
this._loading.set(true);
this._error.set(null);
this.http.get<Task[]>('/api/tasks').pipe(
tap(tasks => this._tasks.set(tasks)),
catchError(err => {
this._error.set('Failed to load tasks. Please try again.');
return EMPTY;
}),
finalize(() => this._loading.set(false))
).subscribe();
}
updateStatus(taskId: string, status: TaskStatus): void {
// Optimistic update: update UI immediately
this._tasks.update(current =>
current.map(t => t.id === taskId ? { ...t, status } : t)
);
this.http.patch<Task>(`/api/tasks/#123;taskId}`, { status }).pipe(
catchError(() => {
// Rollback on error
this.loadTasks();
this._error.set('Failed to update task status.');
return EMPTY;
})
).subscribe();
}
}
Phase 4 - SSR and Incremental Hydration with Cursor
Angular 19 brings incremental hydration to stable. This feature lets you hydrate only the parts of the page that become visible or interactive, dramatically reducing initial JavaScript. Configuring SSR correctly is one of the most error-prone areas, which is exactly where Cursor adds the most value.
Prompt: Configure SSR with Incremental Hydration
Configure SSR with incremental hydration for this Angular 19 project. Make these changes:
1. In app.config.ts: add provideClientHydration(withIncrementalHydration())
2. Create a PlatformService (src/app/core/services/platform.service.ts)
that uses PLATFORM_ID to detect execution context
3. In TaskListComponent: wrap the task list in a @defer block with
on viewport for lazy loading + incremental hydration
4. Add TransferState to avoid double HTTP calls in TaskService
(load data server-side, transfer to client without refetch)
5. Handle the case where localStorage is unavailable server-side
// app.config.ts - Complete SSR configuration
import { ApplicationConfig, provideZonelessChangeDetection } from '@angular/core';
import { provideRouter, withPreloading, PreloadAllModules } from '@angular/router';
import { provideClientHydration, withIncrementalHydration } from '@angular/platform-browser';
import { provideHttpClient, withFetch } from '@angular/common/http';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [
// Zone-less change detection (Angular 18+, recommended with signals)
provideZonelessChangeDetection(),
// Router with preloading strategy
provideRouter(routes, withPreloading(PreloadAllModules)),
// HTTP with fetch API (SSR-compatible)
provideHttpClient(withFetch()),
// SSR Incremental Hydration (Angular 19 stable)
provideClientHydration(withIncrementalHydration()),
]
};
Phase 5 - AI-Guided Testing Workflow
Testing is often the most neglected part of professional development because it feels burdensome. Cursor changes this equation: you can generate a complete test suite in minutes, allowing you to focus on reviewing the logic and adding edge cases instead of writing boilerplate from scratch.
Prompt: Generate Complete Unit Tests
Generate complete unit tests for @task.service.ts using Jest and Angular Testing Utilities.
Include tests for:
1. loadTasks(): success (HTTP 200 mock), error (HTTP 500 mock),
loading state during call, TransferState usage during hydration
2. createTask(): signal update, rollback on error,
verify new task is appended to the end
3. updateStatus(): optimistic update, verify signal updates immediately,
HTTP error rollback
4. Computed signals: verify completedTasks and pendingTasks update
correctly when _tasks changes
Use TestBed with provideHttpClientTesting, HttpTestingController for HTTP mocks.
Organize with nested describe/it blocks. Add afterEach with httpMock.verify().
// task.service.spec.ts - Generated by Cursor
import { TestBed } from '@angular/core/testing';
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
import { provideHttpClient } from '@angular/common/http';
import { TaskService } from './task.service';
import { Task } from '../models/task.model';
const mockTasks: Task[] = [
{ id: '1', title: 'Task 1', description: '', status: 'todo', priority: 'high',
createdAt: new Date(), dueDate: null, assigneeId: null },
{ id: '2', title: 'Task 2', description: '', status: 'done', priority: 'low',
createdAt: new Date(), dueDate: null, assigneeId: null }
];
describe('TaskService', () => {
let service: TaskService;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [provideHttpClient(), provideHttpClientTesting(), TaskService]
});
service = TestBed.inject(TaskService);
httpMock = TestBed.inject(HttpTestingController);
});
afterEach(() => httpMock.verify());
describe('loadTasks()', () => {
it('should load tasks and update the signal', () => {
service.loadTasks();
const req = httpMock.expectOne('/api/tasks');
expect(req.request.method).toBe('GET');
req.flush(mockTasks);
expect(service.tasks()).toEqual(mockTasks);
expect(service.loading()).toBe(false);
expect(service.error()).toBeNull();
});
it('should set loading to true during the call', () => {
service.loadTasks();
expect(service.loading()).toBe(true);
httpMock.expectOne('/api/tasks').flush(mockTasks);
expect(service.loading()).toBe(false);
});
it('should handle HTTP errors and set error signal', () => {
service.loadTasks();
httpMock.expectOne('/api/tasks').flush(
{ message: 'Server Error' },
{ status: 500, statusText: 'Internal Server Error' }
);
expect(service.error()).toBe('Failed to load tasks. Please try again.');
expect(service.loading()).toBe(false);
});
});
describe('Computed Signals', () => {
it('completedTasks should filter only tasks with done status', () => {
service.loadTasks();
httpMock.expectOne('/api/tasks').flush(mockTasks);
expect(service.completedTasks()).toHaveLength(1);
expect(service.completedTasks()[0].id).toBe('2');
});
it('completionRate should calculate the correct percentage', () => {
service.loadTasks();
httpMock.expectOne('/api/tasks').flush(mockTasks);
expect(service.completionRate()).toBe(50);
});
});
});
E2E Tests with Playwright
Prompt: Playwright E2E Test
Generate Playwright E2E tests for the "Create and complete a Task" flow.
Scenario:
1. User opens the dashboard (/)
2. Clicks "New Task" button
3. Fills form: title "E2E Test Task", priority "high", no due date
4. Clicks "Save"
5. Verifies the new task appears in the list with status "todo"
6. Clicks "mark as complete" on the new task
7. Verifies status becomes "done" and task appears in completed section
8. Verifies completionRate shows a value > 0%
Use page object pattern. Mock backend with Playwright apiRoutes.
Add accessibility check with axe-core on each screen.
Phase 6 - Refactoring Legacy Patterns
One of the most common use cases in teams with existing codebases is migrating legacy Angular
code (NgModules, @Input()/@Output(),
*ngIf/*ngFor) to modern patterns. Cursor excels at this kind of
systematic refactoring.
Prompt: Migrate to Standalone and Signals
Migrate @legacy-user-profile.component.ts to:
1. Standalone component (remove from NgModule)
2. Replace @Input() with input() signal
3. Replace @Output() EventEmitter with output()
4. Convert template from *ngIf/*ngFor to @if/@for
5. Add ChangeDetectionStrategy.OnPush
6. If uses ngModel, convert to reactive form with typed FormControl
7. Update spec file to reflect the changes
After each change explain the rationale and performance benefits.
Plan Mode for Large-Scale Migrations
For large-scale migrations (entire modules or applications), always use Plan Mode before Agent Mode. This lets you review the plan before Cursor makes potentially irreversible changes:
Prompt: Plan Mode for Module Migration
[Enable Plan Mode with Ctrl+Shift+P → "Plan Mode ON"]
Analyze the UserModule (@src/app/modules/user/) and create a detailed plan
to migrate it to standalone components with signals. The module has:
- UserModule.ts (main NgModule)
- 4 components: UserListComponent, UserCardComponent, UserDetailComponent, UserEditComponent
- 2 services: UserService, UserPreferencesService
- 1 guard: UserAuthGuard
For each file:
1. List the required changes
2. Identify dependencies to update
3. Estimate risk (Low/Medium/High) with reasoning
4. Suggest migration order to minimize risk
DO NOT make any changes yet - plan only.
Phase 7 - AI-Assisted Performance Optimization
Performance is an area where Cursor can make a real difference, but it requires you to ask the right questions. The AI does not automatically identify all performance problems: you need to guide it with specific context about the problem you are solving.
Prompt: Bundle Analysis and Lazy Loading
Analyze @app.routes.ts and @app.config.ts. I ran "ng build --stats-json" and
the main bundle is 850KB (too large).
Make these optimizations:
1. Convert all routes to lazy-loaded (use loadComponent for standalone)
2. Add intelligent PreloadStrategy: PreloadAllModules for main routes,
no preload for admin/settings routes rarely visited
3. Identify heavy imports in the main bundle to move to lazy chunks
4. Configure budgets in angular.json: warning at 500KB, error at 1MB
// app.routes.ts - Optimized by Cursor with lazy loading
import { Routes } from '@angular/router';
export const routes: Routes = [
{
path: '',
redirectTo: 'dashboard',
pathMatch: 'full'
},
{
path: 'dashboard',
loadComponent: () =>
import('./features/dashboard/dashboard.component').then(m => m.DashboardComponent),
title: 'Dashboard - Task Manager'
},
{
path: 'tasks',
loadChildren: () =>
import('./features/tasks/tasks.routes').then(m => m.TASKS_ROUTES),
title: 'Tasks - Task Manager'
},
{
path: 'settings',
loadComponent: () =>
import('./features/settings/settings.component').then(m => m.SettingsComponent),
// No preload: rarely accessed
data: { preload: false },
title: 'Settings - Task Manager'
},
{
path: '**',
loadComponent: () =>
import('./shared/components/not-found/not-found.component').then(m => m.NotFoundComponent)
}
];
Phase 8 - CI/CD Pipeline Generated with Cursor
The final phase of every professional project is automating deployment. Cursor can generate complete, optimized GitHub Actions pipelines including caching strategies, parallel tests, and conditional deploys based on branch.
Prompt: Complete GitHub Actions Pipeline
Create a complete GitHub Actions pipeline for this Angular 19 project with:
CI WORKFLOW (.github/workflows/ci.yml):
- Trigger: push on feature/*, pull_request to main and develop
- Parallel jobs: lint, unit-tests, build
- Cache node_modules keyed on package-lock.json
- Unit tests with Jest + coverage report (minimum 80% threshold)
- Upload coverage to Codecov
- Production build with --stats-json
- PR comment with bundle size comparison vs base branch
CD WORKFLOW (.github/workflows/cd.yml):
- Trigger: push to main (after CI passes)
- Deploy staging on develop push
- Deploy production on main push with manual approval
- Deploy to Firebase Hosting (use secrets: FIREBASE_TOKEN)
- Post-deploy smoke test: verify / responds 200 and bundle is < 1MB
- Slack notification on failure
Use Node.js 22, npm ci for deterministic installation.
# .github/workflows/ci.yml - Generated by Cursor
name: CI
on:
push:
branches: ['feature/**', 'fix/**']
pull_request:
branches: [main, develop]
concurrency:
group: #123;{ github.workflow }}-#123;{ github.ref }}
cancel-in-progress: true
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- run: npm ci
- run: npm run lint
test:
name: Unit Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- run: npm ci
- name: Run Jest with coverage
run: npm test -- --coverage --coverageThreshold='{"global":{"branches":80,"functions":80,"lines":80}}'
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
token: #123;{ secrets.CODECOV_TOKEN }}
build:
name: Production Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- run: npm ci
- name: Build with stats
run: npm run build -- --stats-json
- name: Bundle size check
run: |
BUNDLE_SIZE=$(stat -c%s dist/browser/main.*.js)
echo "Bundle size: $BUNDLE_SIZE bytes"
if [ $BUNDLE_SIZE -gt 1048576 ]; then
echo "::error::Bundle size exceeds 1MB limit"
exit 1
fi
Case Study: "Real-Time Notifications" Feature from Idea to Deploy
To consolidate everything we have covered, let us walk through how a professional developer completes the entire lifecycle of a feature using Cursor. The feature: adding real-time notifications when a task is assigned or changes status.
Step 1 - Plan Mode: Feature Architecture
Plan Mode Prompt
[Plan Mode ON]
I want to add real-time notifications using WebSocket for these events:
- task_assigned: when a task is assigned to the current user
- task_status_changed: when a task the user owns changes status
- task_due_soon: 24h before a task deadline
Create an architectural plan that includes:
1. WebSocket service (with automatic reconnect)
2. NotificationCenter component (slide-in panel)
3. NotificationBadge component (navbar icon with counter)
4. Integration with existing TaskService
5. Unread notifications persistence in localStorage
6. Testing strategy
Consider: SSR (WebSocket unavailable server-side),
performance (no memory leaks), accessibility (screen reader for live notifications).
DO NOT make any changes yet - plan only.
Step 2 - Agent Mode: Implementation
// notification.service.ts - Generated after plan approval
import { Injectable, inject, signal, computed, effect, OnDestroy } from '@angular/core';
import { PlatformService } from '../../../core/services/platform.service';
export interface Notification {
id: string;
type: 'task_assigned' | 'task_status_changed' | 'task_due_soon';
message: string;
taskId: string;
timestamp: Date;
read: boolean;
}
@Injectable({ providedIn: 'root' })
export class NotificationService implements OnDestroy {
private readonly platform = inject(PlatformService);
private socket: WebSocket | null = null;
private reconnectTimer: ReturnType<typeof setTimeout> | null = null;
private readonly _notifications = signal<Notification[]>([]);
readonly notifications = this._notifications.asReadonly();
readonly unreadCount = computed(() =>
this._notifications().filter(n => !n.read).length
);
readonly hasUnread = computed(() => this.unreadCount() > 0);
constructor() {
// Load persisted notifications from localStorage (browser only)
if (this.platform.isBrowser) {
this._loadPersistedNotifications();
this._initWebSocket();
}
// Auto-persist when notifications change
effect(() => {
const notifications = this._notifications();
this.platform.setLocalStorage(
'notifications',
JSON.stringify(notifications.slice(0, 50)) // Keep max 50
);
});
}
markAsRead(notificationId: string): void {
this._notifications.update(current =>
current.map(n => n.id === notificationId ? { ...n, read: true } : n)
);
}
markAllAsRead(): void {
this._notifications.update(current =>
current.map(n => { ...n, read: true })
);
}
private _initWebSocket(): void {
this.socket = new WebSocket('wss://api.example.com/notifications');
this.socket.onmessage = (event) => {
const notification: Notification = {
...JSON.parse(event.data),
// Fallback for environments where crypto.randomUUID is unavailable
id: typeof crypto !== 'undefined' && crypto.randomUUID
? crypto.randomUUID()
: `#123;Date.now()}-#123;Math.random().toString(36).slice(2)}`,
timestamp: new Date(),
read: false
};
this._notifications.update(current => [notification, ...current]);
};
this.socket.onclose = () => {
// Auto-reconnect with exponential backoff
this.reconnectTimer = setTimeout(() => this._initWebSocket(), 3000);
};
}
private _loadPersistedNotifications(): void {
const stored = this.platform.getLocalStorage('notifications');
if (stored) {
try {
this._notifications.set(JSON.parse(stored));
} catch {
// Malformed JSON - ignore silently
}
}
}
ngOnDestroy(): void {
this.socket?.close();
if (this.reconnectTimer) clearTimeout(this.reconnectTimer);
}
}
Tips and Tricks for Angular Developers
1. Use @codebase for Project-Aware Questions
Prompt Pattern: Codebase Context
// LESS EFFECTIVE
"How do I add pagination to tasks?"
// MORE EFFECTIVE
"@codebase Looking at TaskListComponent and TaskService,
how do I add server-side pagination (page + pageSize params on GET /api/tasks)
using the signals and HTTP service patterns already in the project?"
2. The "Critical Review" Prompt
Prompt: Specialized Code Review
Review @task.service.ts as a senior Angular developer focused on:
- Performance: unnecessary computed(), effect() that could cause loops,
signal updates triggering unnecessary re-renders
- Memory: unsubscribed subscriptions, uncleared timers,
circular references in signals
- Security: XSS in templates, injection in HTTP parameters
- Angular 2025 best practices: is anything deprecated?
Give ONLY concrete feedback with code snippets. Skip praise.
3. Document with Cursor, Not Manually
Prompt: Generate JSDoc and README
For every public method in @notification.service.ts add JSDoc with:
- @description: what the method does
- @param: type and purpose of each parameter
- @returns: what it returns and under what conditions
- @throws: if the method can throw and under what conditions
- @example: a concise usage example
Then generate a README.md for the notifications feature in
src/app/features/notifications/ documenting NotificationService
for a new team developer.
4. Background Agents for Long-Running Tasks
Cursor 2.0 Background Agents are ideal for tasks that require more time, like analyzing an entire codebase or generating tests for dozens of components. While the agent works, you can keep developing in parallel:
Prompt: Background Agent for Test Coverage
[Background Agent]
Analyze all components in src/app/features/ that have test coverage below 80%.
For each component with insufficient coverage:
1. Identify uncovered cases (branches, public functions, error paths)
2. Write the missing tests
3. Verify npm test passes after each addition
Work in priority order: first components with 0% coverage,
then those below 50%, then between 50% and 80%.
Notify me when finished with a coverage summary.
Real Productivity Metrics
A legitimate question is: "How much time do I actually save with Cursor?" Based on documented experiences from teams that have adopted Cursor for professional Angular projects:
Benchmark: Angular Project with vs. without Cursor
| Activity | Without Cursor | With Cursor | Savings |
|---|---|---|---|
| Project bootstrap (CLI + Jest/ESLint/Prettier config) | 45-60 min | 5-10 min | ~85% |
| Generate complete feature (model + service + 4 components + routing) | 3-4 hours | 30-45 min | ~80% |
| Write unit tests (80% coverage) | 2 hours per service | 20-30 min | ~75% |
| Migrate legacy component to standalone + signals | 30-45 min | 5-10 min | ~80% |
| Setup GitHub Actions CI/CD | 2-3 hours | 20-30 min | ~85% |
| Debug a complex bug | 1-2 hours | 20-40 min | ~60% |
When Cursor Falls Short
Cursor is a productivity multiplier, not a replacement for expertise. There are situations where the AI shows its limitations in an Angular context:
- Strategic architectural decisions: Cursor can propose options, but choosing the right state management strategy (signals vs NgRx vs Akita) depends on business factors only you know.
- Advanced performance debugging: Identifying a memory leak caused by a closure in an effect() or a cyclic re-render between signals requires deep understanding of Angular's change detection.
- Security review: Never blindly trust generated code without a security review. Cursor can introduce subtle vulnerabilities, especially around authentication handling and input sanitization.
Anti-Patterns to Avoid with Cursor and Angular
Anti-Pattern 1: Accepting Code Without Reading It
The biggest risk when using Cursor is becoming so dependent on the AI that you accept generated code without understanding it. This leads to inconsistent codebases, hard-to-debug bugs, and developers who do not understand their own code.
Practical rule: If you cannot explain to a colleague why the generated code does what it does, do not accept it until you understand it. Use Cursor to accelerate, not to bypass comprehension.
Anti-Pattern 2: Vague Prompts for Complex Problems
// VAGUE PROMPT - mediocre result
"The task list doesn't update after changing a status"
// SPECIFIC PROMPT - accurate result
"@task-list.component.ts @task.service.ts
When I call updateStatus() in TaskService, the _tasks signal is updated
(verified with debugger that the value changes), but TaskListComponent does NOT
show the change. The component uses OnPush. I verified the [tasks] input
is passed from a parent component using async pipe.
Could the issue be with signal reference immutability?"
Anti-Pattern 3: Contradictory Rules
If you have rules that contradict each other (for example, one rule says "use signals" and another says "use BehaviorSubject for state"), Cursor will produce inconsistent code. Do periodic audits of your rules to remove conflicts and update obsolete ones as you migrate the codebase.
Conclusions: The Angular Developer Workflow in 2026
We have reached the end of this article and the entire Cursor IDE series. The workflow we have built represents the state of the art in professional Angular development in 2026: an AI-native but developer-controlled approach, where artificial intelligence accelerates every phase without replacing human judgment.
Summarizing the complete workflow:
- Rules Configuration: Invest time in creating stack-specific rules. This is the biggest multiplier: each well-written rule improves every future AI interaction.
- Plan Mode Before Agent Mode: For complex features or migrations, always plan before executing. A reviewed plan is faster than a wrong implementation.
- Agent Mode for Bootstrap: Let the AI handle structure, component, and configuration creation. Your time is too valuable for boilerplate.
- AI-Assisted Testing: Generate tests with Cursor, review edge cases, add the cases the AI missed. Achieve 80% coverage in a quarter of the time.
- Assisted Refactoring: Use Cursor for systematic migrations to modern patterns (signals, standalone, new syntax). Scale to entire modules with Background Agents.
- Generated CI/CD: Do not write YAML pipelines by hand. Describe requirements and let Cursor generate correct, optimized configurations.
The developer who embraces this workflow does not become less skilled: they become exponentially more productive. Expertise remains essential for evaluating generated code, making architectural decisions, and maintaining project quality. Cursor is not a leveler: it amplifies the capabilities of those who are already good.
Cursor IDE and AI-Native Development Series Summary
| # | Article | Main Focus |
|---|---|---|
| 1 | Cursor IDE: The Complete Guide | Overview, installation, core features |
| 2 | Cursor Rules | Configuring AI for your project |
| 3 | Agent Mode | Modifying the codebase with one command |
| 4 | Plan Mode and Background Agents | Planning and parallelism |
| 5 | Cursor Hooks | Workflow automation |
| 6 | MCP and Cursor | Connecting to databases and APIs |
| 7 | Debugging with Cursor AI | Bug fixing 3x faster |
| 8 | Cursor vs Windsurf vs Copilot | Tool comparison in 2026 |
| 9 | You are here - Professional Angular Workflow | Complete case study from setup to deploy |
Related Series to Explore
- Angular Moderno (IDs 224-233): Deep dive into signals, standalone components, SSR, and the latest Angular features with dedicated guides.
- MCP and Cursor (IDs 64-77): Explore the Model Context Protocol in detail to connect Cursor to databases, APIs, and external tools.
- Vibe Coding: Discover how developers use AI to rapidly prototype ideas, with Claude Code, multi-agent systems, and AI code testing.
Thank you for following the entire series. If you have questions, feedback, or want to share your own Angular workflow with Cursor, leave a comment below. Your contribution helps improve these guides for the entire developer community.







