전문적인 작업 흐름: 구성에서 배포까지 커서가 있는 Angular 프로젝트
커서, 해당 규칙, 에이전트 모드, 계획 모드, 후크 및 MCP 프로토콜에 대해 배웠습니다. 이제 모든 것을 하나로 모아야 할 때입니다 진정한 전문적인 작업 흐름. 이 기사 시리즈의 마지막과 운영 사례 연구: Cursor를 사용하여 완전한 Angular 프로젝트를 구축하겠습니다. 프로젝트 초기화부터 프로덕션 배포까지 모든 단계에서 AI 부조종사를 맡습니다.
이것은 모범 사례를 추상적으로 모아 놓은 것이 아닙니다. 각 섹션에는 실제 명령, 프롬프트가 표시됩니다. 효과적이고 구체적인 구성과 통합 시 전문 팀이 내리는 결정 일일 개발 프로세스에 커서를 놓습니다. 이 기사가 끝나면 플레이북이 제공됩니다. 모든 Angular 프로젝트에 대해 완전하고 복제 가능합니다.
우리가 만들 프로젝트는 하나입니다 작업 관리 대시보드 Angular 19, SSR, GitHub Actions를 사용한 신호, 독립 실행형 구성 요소, 자동화된 테스트 및 CI/CD. 프로젝트 일상적인 전문 업무에서 직면하는 실제 복잡성을 나타냅니다.
이 기사에서 배울 내용
- 파일을 구조화하는 방법
.cursor/rules/Angular 프로젝트에 최적 - 에이전트 모드를 사용한 초기 프로젝트 설정: 처음부터 몇 분 안에 구조 완료
- 신호 및 반응 형식을 갖춘 AI 기반 독립형 구성 요소 생성
- 커서를 보조자로 사용하는 SSR 및 증분 수화 구성
- 테스트 워크플로: AI로 작성된 Jest/Vitest 및 Playwright를 사용한 E2E를 사용한 단위 테스트
- 에이전트 모드를 사용하여 레거시 패턴을 지능적으로 리팩터링
- 성능 최적화 지원: 지연 로딩, 번들 분석, Core Web Vitals
- GitHub Actions 및 Firebase용 Cursor를 사용하여 생성된 완전한 CI/CD 파이프라인
- 엔드투엔드 사례 연구: 아이디어부터 프로덕션 배포까지 전체 기능
- Cursor를 매일 사용하는 Angular 개발자를 위한 독점 팁과 요령
기술 요구 사항
- Node.js 22+ 및 Angular CLI 19+
- 커서 IDE(무제한 에이전트 모드에는 Pro 계획 권장)
- CI/CD용 Git 및 GitHub 계정
- Angular, TypeScript 및 RxJS에 대한 기본 지식
- 선택사항: 배포용 Firebase 계정, SSR에 대한 지식
1단계 - Angular 프로젝트에 대한 커서 규칙 구성
전문적인 작업 흐름의 첫 번째 단계는 커서가 다음을 알 수 있도록 구성하는 것입니다. 첫 번째 코드 줄을 작성하기도 전에 프로젝트의 규칙을 따르세요. 파일 잘 구조화된 규칙은 Cursor를 일반 보조자에서 협력자 Angular 스택에 특화된.
Cursor 0.45+를 사용하면 규칙이 디렉토리에 있습니다. .cursor/rules/ 파일로
.mdc. 항상 활성화된 전역 규칙과 실행되는 특정 규칙을 가질 수 있습니다.
상황에 따라. 전문적인 Angular 프로젝트의 경우 다음 구조를 권장합니다.
# Struttura directory regole Angular
.cursor/
rules/
angular-core.mdc # Regole fondamentali sempre attive
angular-components.mdc # Regole per componenti standalone
angular-testing.mdc # Regole per la scrittura dei test
angular-performance.mdc # Regole per ottimizzazioni
angular-ssr.mdc # Regole per SSR e hydration
전체 내용은 다음과 같습니다. angular-core.mdc, 가장 중요한 규칙은
프로젝트의 아키텍처 기반을 구축합니다.
---
description: Regole fondamentali per progetti Angular 19+ con standalone components e signals
globs: ["**/*.ts", "**/*.html"]
alwaysApply: true
---
# Angular Core Rules
## Architettura e Struttura
- Usa SEMPRE standalone components (niente NgModules salvo casi eccezionali)
- Organizza per feature/dominio, non per tipo (no cartelle globali "components/", "services/")
- Struttura directory per feature: `src/app/features/[nome-feature]/`
- Ogni feature ha: components/, services/, models/, guards/ (se necessario)
- Shared components in `src/app/shared/`
- Core singleton services in `src/app/core/`
## TypeScript e Dependency Injection
- Usa SEMPRE `inject()` per l'iniezione delle dipendenze (non costruttore)
- TypeScript strict mode obbligatorio
- Evita `any` - usa `unknown` con type narrowing quando necessario
- Usa `readonly` per proprietà che non cambiano dopo l'inizializzazione
- Interface su Type per definire shape di oggetti
## State Management con Signals
- Usa signals per tutto lo stato locale del componente
- `computed()` per valori derivati, mai getters che chiamano funzioni
- `effect()` solo per side effects (DOM, chiamate API non-reactive, log)
- Per stato condiviso tra componenti: service con signals esposti come readonly
- RxJS per operazioni async complesse (HTTP, WebSocket), poi `toSignal()` per esporre nei template
## Template e Rendering
- Usa SEMPRE la nuova sintassi control flow: @if, @for, @switch (non *ngIf, *ngFor)
- `@for` richiede sempre il `track` expression - usa ID univoci, non index
- ChangeDetectionStrategy.OnPush per TUTTI i componenti (performance default)
- NgOptimizedImage per tutte le immagini (src → ngSrc)
## Naming Conventions
- File: kebab-case (`user-profile.component.ts`)
- Classi: PascalCase (`UserProfileComponent`)
- Signals: nome senza prefisso, non `
09 - 전문적인 작업 흐름: 커서가 있는 각도 프로젝트 | Federico Calò
09 - 전문적인 작업 흐름: 커서가 있는 각도 프로젝트 | Federico Calò
Salta al contenuto principale안녕하세요!
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.
소개
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.
역량
Analisi Dati & Modelli Previsionali
Trasformo i dati in insights strategici con analisi approfondite e modelli predittivi per decisioni informate
프로세스 자동화
Creo strumenti personalizzati che automatizzano operazioni ripetitive e liberano tempo per attività a valore aggiunto
맞춤 시스템
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"
]
};
미션
Credo fermamente che l'informatica sia lo strumento più potente per trasformare le idee in realtà e migliorare la vita delle persone.
기술의 민주화
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.
IT와 비즈니스 통합
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à.
맞춤 솔루션
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.
기술로 비즈니스를 혁신하세요
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.
상담하기 →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🌿Git연락하기
프로젝트가 있으신가요? 아래 양식을 작성해 주시면 빠르게 답변드리겠습니다.
* Campi obbligatori. I tuoi dati saranno utilizzati solo per rispondere alla tua richiesta.
come suffisso (`users`, non `users
09 - 전문적인 작업 흐름: 커서가 있는 각도 프로젝트 | Federico Calò
09 - 전문적인 작업 흐름: 커서가 있는 각도 프로젝트 | Federico Calò
Salta al contenuto principale안녕하세요!
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.
소개
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.
역량
Analisi Dati & Modelli Previsionali
Trasformo i dati in insights strategici con analisi approfondite e modelli predittivi per decisioni informate
프로세스 자동화
Creo strumenti personalizzati che automatizzano operazioni ripetitive e liberano tempo per attività a valore aggiunto
맞춤 시스템
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"
]
};
미션
Credo fermamente che l'informatica sia lo strumento più potente per trasformare le idee in realtà e migliorare la vita delle persone.
기술의 민주화
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.
IT와 비즈니스 통합
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à.
맞춤 솔루션
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.
기술로 비즈니스를 혁신하세요
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.
상담하기 →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🌿Git연락하기
프로젝트가 있으신가요? 아래 양식을 작성해 주시면 빠르게 답변드리겠습니다.
* Campi obbligatori. I tuoi dati saranno utilizzati solo per rispondere alla tua richiesta.
ne `usersSignal`)
- Observable: suffisso `
09 - 전문적인 작업 흐름: 커서가 있는 각도 프로젝트 | Federico Calò
09 - 전문적인 작업 흐름: 커서가 있는 각도 프로젝트 | Federico Calò
Salta al contenuto principale안녕하세요!
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.
소개
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.
역량
Analisi Dati & Modelli Previsionali
Trasformo i dati in insights strategici con analisi approfondite e modelli predittivi per decisioni informate
프로세스 자동화
Creo strumenti personalizzati che automatizzano operazioni ripetitive e liberano tempo per attività a valore aggiunto
맞춤 시스템
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"
]
};
미션
Credo fermamente che l'informatica sia lo strumento più potente per trasformare le idee in realtà e migliorare la vita delle persone.
기술의 민주화
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.
IT와 비즈니스 통합
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à.
맞춤 솔루션
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.
기술로 비즈니스를 혁신하세요
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.
상담하기 →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🌿Git연락하기
프로젝트가 있으신가요? 아래 양식을 작성해 주시면 빠르게 답변드리겠습니다.
* Campi obbligatori. I tuoi dati saranno utilizzati solo per rispondere alla tua richiesta.
(`users
09 - 전문적인 작업 흐름: 커서가 있는 각도 프로젝트 | Federico Calò
09 - 전문적인 작업 흐름: 커서가 있는 각도 프로젝트 | Federico Calò
Salta al contenuto principale안녕하세요!
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.
소개
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.
역량
Analisi Dati & Modelli Previsionali
Trasformo i dati in insights strategici con analisi approfondite e modelli predittivi per decisioni informate
프로세스 자동화
Creo strumenti personalizzati che automatizzano operazioni ripetitive e liberano tempo per attività a valore aggiunto
맞춤 시스템
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"
]
};
미션
Credo fermamente che l'informatica sia lo strumento più potente per trasformare le idee in realtà e migliorare la vita delle persone.
기술의 민주화
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.
IT와 비즈니스 통합
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à.
맞춤 솔루션
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.
기술로 비즈니스를 혁신하세요
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.
상담하기 →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🌿Git연락하기
프로젝트가 있으신가요? 아래 양식을 작성해 주시면 빠르게 답변드리겠습니다.
* Campi obbligatori. I tuoi dati saranno utilizzati solo per rispondere alla tua richiesta.
)
- Metodi privati: prefisso `_` quando servono chiarezza
## Forms
- Reactive Forms (ReactiveFormsModule) per tutti i form non banali
- Template-driven solo per form con 1-2 campi senza validazione complessa
- Typed forms obbligatori (`FormControl<string>`, non `FormControl`)
- Validators personalizzati come funzioni pure (non classi)
이 규칙은 Cursor에 전체 아키텍처 컨텍스트를 제공합니다. 생성을 요청하면
구성 요소, 서비스 또는 기능 중 어느 것을 사용할지 커서가 자동으로 인식합니다.
inject(), 신호 및 새로운 제어 흐름 구문. 그럴 필요는 없습니다
프롬프트에서 매번 반복하십시오.
흔한 실수: 너무 일반적인 규칙
여러 팀이 단일 파일을 만듭니다. .cursorrules 수백 줄로 거대합니다.
결과적으로 커서는 해당 작업과 가장 관련된 지침의 우선 순위를 지정하지 못합니다.
현재 상황. 특정 glob 패턴이 있는 별도의 파일 사용: i에 대한 규칙
구성요소는 다음에서만 활성화됩니다. *.component.ts, 컨텍스트 유지
집중적이고 가장 정확한 답변을 제공합니다.
구성요소 규칙: angle-comComponents.mdc
---
description: Standard per la creazione di componenti Angular standalone
globs: ["**/*.component.ts", "**/*.component.html"]
alwaysApply: false
---
# Component Standards
## Struttura Component File (ordine canonico)
1. Imports Angular/librerie
2. Imports locali (services, models, altri components)
3. @Component decorator
4. export class ComponentName
a. inject() calls (services)
b. @Input() signals con input()
c. @Output() signals con output()
d. Signals interni (private)
e. Computed signals
f. Constructor (solo se necessario per logic inizializzazione)
g. ngOnInit (se necessario)
h. Metodi pubblici (chiamati dal template)
i. Metodi privati (logica interna)
## Template Best Practices
- Niente logica nel template oltre a binding semplici
- Usa pipe per trasformazioni di dati (DatePipe, CurrencyPipe, ecc.)
- Mantieni template sotto le 100 righe - estrai sub-component se necessario
- Usa `aria-*` per accessibilità (WCAG 2.1 AA)
## Input/Output con Signal API (Angular 17+)
- `input()` per input opzionali, `input.required()` per quelli obbligatori
- `output()` al posto di `EventEmitter`
- `model()` per two-way binding custom
## Component-Scoped Styles
- Usa `:host` per stili sul root element
- Evita deep selector `::ng-deep` - estrai stili globali se necessario
- Variabili CSS per colori e spacing (usa il design system del progetto)
2단계 - 에이전트 모드를 사용한 프로젝트 설정
규칙이 구성되었으면 이제 프로젝트를 생성할 차례입니다. 수동으로 실행하는 대신 각 명령을 실행하고 각 파일을 생성한 후 에이전트 모드를 사용하여 전체 부트스트랩 단계를 위임합니다. 이는 커서의 가장 강력한 사용 사례 중 하나입니다. 높은 수준의 지침을 제공하고 그대로 둡니다. 에이전트가 모든 작업 단계를 수행한다는 것입니다.
커서를 열고 프로젝트에 대한 새 폴더를 생성한 다음 다음을 사용하여 에이전트 모드를 시작합니다. Cmd+Shift+I (또는 Windows/Linux에서는 Ctrl+Shift+I). 그런 다음 다음 프롬프트를 사용하십시오.
프롬프트 에이전트 모드: 부트스트랩 프로젝트
Crea un nuovo progetto Angular 19 chiamato "task-dashboard" con le seguenti caratteristiche:
1. Angular CLI con SSR abilitato (--ssr flag)
2. TypeScript strict mode
3. Jest al posto di Karma per i test unitari (configura jest.config.ts)
4. ESLint con angular-eslint
5. Prettier configurato con .prettierrc
6. Struttura a feature:
- src/app/core/ (interceptors, guards, singleton services)
- src/app/shared/ (components e pipes condivisi)
- src/app/features/tasks/ (feature principale)
- src/app/features/auth/ (autenticazione)
7. Ambiente di sviluppo con proxy verso http://localhost:3000 (API backend)
8. Git inizializzato con .gitignore appropriato
Esegui i comandi necessari, installa le dipendenze e mostrami la struttura finale.
커서가 실행됩니다 ng new, 종속성을 설치하고 Jest를 구성합니다.
ESLint 및 Prettier는 폴더 구조를 생성하고 Git을 초기화합니다.
몇 분 안에. 수동 설정에는 일반적으로 30~45분이 소요됩니다.
정확하고 일관되게 완료되었습니다.
에이전트 모드를 사용한 기능 작업 생성
부트스트래핑 후 주요 기능을 생성합니다. 이 프롬프트는 상담원으로 표시됩니다. 모드는 데이터 모델에서 애플리케이션에 이르기까지 애플리케이션의 전체 수직 조각을 구축할 수 있습니다. Angular 규칙을 준수하는 구성요소:
프롬프트 에이전트 모드: 기능 작업 완료
Crea la feature "tasks" completa in src/app/features/tasks/ seguendo le regole in .cursor/rules/:
MODELLO DATI (src/app/features/tasks/models/task.model.ts):
- Interface Task con: id (string), title (string), description (string),
status ('todo' | 'in-progress' | 'done'), priority ('low' | 'medium' | 'high'),
createdAt (Date), dueDate (Date | null), assigneeId (string | null)
- Type TaskStatus e TaskPriority (union types)
- Interface CreateTaskRequest e UpdateTaskRequest (Partial<Task> senza id/createdAt)
SERVICE (src/app/features/tasks/services/task.service.ts):
- Usa inject(HttpClient)
- Signals: tasks = signal<Task[]>([]), loading = signal(false), error = signal<string | null>(null)
- Computed: completedTasks, pendingTasks, tasksByPriority
- Metodi: loadTasks(), createTask(), updateTask(), deleteTask(), updateStatus()
- Tutti i metodi aggiornano i signals dopo le chiamate HTTP
COMPONENTI STANDALONE:
1. TaskListComponent - lista tasks con filtri per status/priority
2. TaskCardComponent - card singola task con azioni
3. TaskFormComponent - form creazione/modifica con reactive forms tipizzati
4. TaskDetailComponent - vista dettaglio con routing
ROUTING: configura il routing lazy-loaded in tasks.routes.ts
Rispetta SEMPRE: standalone: true, inject(), signals, ChangeDetectionStrategy.OnPush,
@if/@for syntax, TypeScript strict mode.
커서는 규칙에 정의된 규칙을 준수하는 모든 파일을 생성합니다. 결과 그리고 여러분이 직접 작성할 수도 있지만 아주 짧은 시간 안에 일관된 코드를 작성할 수 있습니다.
3단계 - 신호 및 반응형 양식이 포함된 구성 요소
Cursor가 최신 Angular 구성요소를 생성하는 방법을 자세히 살펴보겠습니다. 프롬프트를 준 후
위에서 출력을 살펴보겠습니다. TaskFormComponent 이를 개선하는 방법은 다음과 같습니다.
// task-form.component.ts - Generato da Cursor con 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 con inject()
private readonly fb = inject(FormBuilder);
private readonly taskService = inject(TaskService);
// Input signals (Angular 17+ API)
readonly initialData = input<Partial<CreateTaskRequest> | null>(null);
readonly isEdit = input(false);
// Output signals
readonly formSubmit = output<CreateTaskRequest>();
readonly formCancel = output<void>();
// Reactive form tipizzato
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)
});
// Computed: stato di validita esposto al template
readonly isValid = this.form.statusChanges;
// Loading state dal service (readonly - no mutation)
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();
}
}
Cursor가 어떻게 규칙 규칙을 자동으로 준수하는지 확인하세요. inject()
중독에 대한, input() e output() 대신에
@Input() e @Output(), readonly 속성에
전자 ChangeDetectionStrategy.OnPush. 이것이 바로 규칙의 실제 가치입니다.
구성됨: AI는 검토 없이 팀 표준을 준수하는 코드를 생성합니다.
상수.
신호가 있는 TaskService: 전체 반응 패턴
// task.service.ts - Pattern signals per stato globale della feature
import { Injectable, inject, signal, computed } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Task, CreateTaskRequest, UpdateTaskRequest, TaskStatus } from '../models/task.model';
import { tap, catchError, EMPTY, finalize } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class TaskService {
private readonly http = inject(HttpClient);
private readonly API_URL = '/api/tasks';
// Signals privati (stato interno del service)
private readonly _tasks = signal<Task[]>([]);
private readonly _loading = signal(false);
private readonly _error = signal<string | null>(null);
// Signals pubblici (readonly - i consumatori non possono mutare)
readonly tasks = this._tasks.asReadonly();
readonly loading = this._loading.asReadonly();
readonly error = this._error.asReadonly();
// Computed signals - derivati dallo stato
readonly completedTasks = computed(() =>
this._tasks().filter(t => t.status === 'done')
);
readonly pendingTasks = computed(() =>
this._tasks().filter(t => t.status !== 'done')
);
readonly tasksByPriority = computed(() => {
const tasks = this._tasks();
return {
high: tasks.filter(t => t.priority === 'high'),
medium: tasks.filter(t => t.priority === 'medium'),
low: tasks.filter(t => t.priority === 'low')
};
});
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[]>(this.API_URL).pipe(
tap(tasks => this._tasks.set(tasks)),
catchError(err => {
this._error.set('Errore nel caricamento dei task. Riprova.');
console.error('[TaskService] loadTasks error:', err);
return EMPTY;
}),
finalize(() => this._loading.set(false))
).subscribe();
}
createTask(request: CreateTaskRequest): void {
this._loading.set(true);
this.http.post<Task>(this.API_URL, request).pipe(
tap(newTask => {
// Immutable update del signal
this._tasks.update(current => [...current, newTask]);
}),
catchError(err => {
this._error.set('Errore nella creazione del task.');
return EMPTY;
}),
finalize(() => this._loading.set(false))
).subscribe();
}
updateStatus(taskId: string, status: TaskStatus): void {
// Optimistic update: aggiorna UI immediatamente
this._tasks.update(current =>
current.map(t => t.id === taskId ? { ...t, status } : t)
);
this.http.patch<Task>(`${this.API_URL}/${taskId}`, { status }).pipe(
catchError(err => {
// Rollback in caso di errore
this.loadTasks();
this._error.set('Errore nell\'aggiornamento dello stato.');
return EMPTY;
})
).subscribe();
}
}
4단계 - 커서를 이용한 SSR 및 증분 수화
각도 19 포트 점진적인 수분공급 stable에서는 다음을 허용하는 기능입니다. 눈에 보이거나 상호 작용할 수 있는 페이지 부분만 수화하여 초기 JavaScript를 대폭 변경했습니다. SSR을 올바르게 구성하는 것은 가장 중요한 영역 중 하나입니다. 미묘한 오류가 있을 수 있습니다. 여기서는 커서가 특히 유용합니다.
증분 하이드레이션 및 적절한 관리로 SSR을 구성하려면 이 프롬프트를 사용하세요. 서버/브라우저 컨텍스트:
프롬프트: 증분 하이드레이션으로 SSR 구성
Configura SSR con hydration incrementale per questo progetto Angular 19. Fai queste modifiche:
1. In app.config.ts: aggiungi provideClientHydration(withIncrementalHydration())
2. Crea un service isPlatformBrowser (src/app/core/services/platform.service.ts)
che usa PLATFORM_ID per verificare il contesto di esecuzione
3. Nel TaskListComponent: avvolgi la lista task in un blocco @defer con
on viewport per il caricamento lazy + hydration incrementale
4. Aggiungi TransferState per evitare la doppia chiamata HTTP nel TaskService
(carica i dati lato server, trasferiscili al client senza refetch)
5. Gestisci il caso in cui localStorage non sia disponibile lato server
커서가 관련 파일을 편집하고 변경 사항을 설명합니다. 결과는 다음과 같습니다
에 app.config.ts 정확하고 플랫폼을 인식하는 서비스:
// app.config.ts - Configurazione SSR completa
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+, raccomandato con signals)
provideZonelessChangeDetection(),
// Router con preloading strategia
provideRouter(routes, withPreloading(PreloadAllModules)),
// HTTP con fetch API (compatibile con SSR nativo)
provideHttpClient(withFetch()),
// SSR Hydration incrementale (Angular 19 stable)
provideClientHydration(withIncrementalHydration()),
]
};
// platform.service.ts - Rilevamento contesto server/browser
import { Injectable, inject, PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser, isPlatformServer } from '@angular/common';
@Injectable({ providedIn: 'root' })
export class PlatformService {
private readonly platformId = inject(PLATFORM_ID);
readonly isBrowser = isPlatformBrowser(this.platformId);
readonly isServer = isPlatformServer(this.platformId);
// Helper per operazioni browser-only
runInBrowser(fn: () => void): void {
if (this.isBrowser) fn();
}
// Safe localStorage access
getLocalStorage(key: string): string | null {
if (!this.isBrowser) return null;
return localStorage.getItem(key);
}
setLocalStorage(key: string, value: string): void {
if (!this.isBrowser) return;
localStorage.setItem(key, value);
}
}
이중 가져오기를 방지하기 위한 TransferState
Angular SSR의 가장 일반적인 오류 중 하나는 데이터가 두 번 로드된다는 것입니다.
렌더링 중에는 서버에, 수화 후에는 다시 클라이언트 측에. 커서 추가 가능
자동으로 TransferState 서비스에:
// task.service.ts - Con TransferState per SSR ottimizzato
import { Injectable, inject, signal, computed, makeStateKey, TransferState } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { tap, catchError, EMPTY, finalize } from 'rxjs';
import { Task, CreateTaskRequest, TaskStatus } from '../models/task.model';
import { PlatformService } from '../../../core/services/platform.service';
const TASKS_KEY = makeStateKey<Task[]>('tasks');
@Injectable({ providedIn: 'root' })
export class TaskService {
private readonly http = inject(HttpClient);
private readonly transferState = inject(TransferState);
private readonly platform = inject(PlatformService);
private readonly _tasks = signal<Task[]>([]);
private readonly _loading = signal(false);
private readonly _error = signal<string | null>(null);
readonly tasks = this._tasks.asReadonly();
readonly loading = this._loading.asReadonly();
readonly error = this._error.asReadonly();
loadTasks(): void {
// Se i dati sono già nel TransferState (hydration), usali direttamente
if (this.transferState.hasKey(TASKS_KEY)) {
const cachedTasks = this.transferState.get(TASKS_KEY, []);
this._tasks.set(cachedTasks);
this.transferState.remove(TASKS_KEY);
return;
}
this._loading.set(true);
this.http.get<Task[]>('/api/tasks').pipe(
tap(tasks => {
this._tasks.set(tasks);
// Lato server: salva nel TransferState per il client
if (this.platform.isServer) {
this.transferState.set(TASKS_KEY, tasks);
}
}),
catchError(() => {
this._error.set('Errore nel caricamento.');
return EMPTY;
}),
finalize(() => this._loading.set(false))
).subscribe();
}
}
5단계 - AI 기반 테스트 워크플로
테스트는 전문성 개발에서 가장 간과되는 부분입니다. 부담스러울 만큼. 커서는 이 방정식을 변경합니다. 완전한 테스트 스위트를 생성할 수 있습니다. 몇 분 안에 케이스 검토 및 완료에 집중할 수 있습니다. 처음부터 상용구를 작성하는 대신 가장자리를 사용하세요.
Jest를 사용한 단위 테스트: 자동 생성
포괄적인 테스트를 받으려면 서비스 또는 구성 요소 파일에서 이 프롬프트를 사용하세요.
프롬프트: 완전한 단위 테스트 생성
Genera unit test completi per @task.service.ts usando Jest e Angular Testing Library.
Includi test per:
1. loadTasks(): successo (mock HTTP 200), errore (mock HTTP 500),
loading state durante la chiamata, utilizzo TransferState in hydration
2. createTask(): aggiornamento ottimista del signal, rollback su errore,
validazione che il nuovo task venga aggiunto in coda
3. updateStatus(): optimistic update, verifica che il signal venga aggiornato
immediatamente, rollback su errore HTTP
4. Computed signals: verifica che completedTasks e pendingTasks si aggiornino
correttamente al cambiamento di _tasks
Usa TestBed con provideHttpClientTesting, HttpTestingController per i mock HTTP.
Organizza con describe/it annidati. Aggiungi afterEach con httpMock.verify().
// task.service.spec.ts - Generato da 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, TaskStatus } 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('dovrebbe caricare i task e aggiornare il 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('dovrebbe impostare loading a true durante la chiamata', () => {
service.loadTasks();
expect(service.loading()).toBe(true);
httpMock.expectOne('/api/tasks').flush(mockTasks);
expect(service.loading()).toBe(false);
});
it('dovrebbe gestire errori HTTP e impostare error signal', () => {
service.loadTasks();
httpMock.expectOne('/api/tasks').flush(
{ message: 'Server Error' },
{ status: 500, statusText: 'Internal Server Error' }
);
expect(service.error()).toBe('Errore nel caricamento.');
expect(service.tasks()).toEqual([]);
expect(service.loading()).toBe(false);
});
});
describe('updateStatus()', () => {
beforeEach(() => {
// Pre-popola il service con task
service.loadTasks();
httpMock.expectOne('/api/tasks').flush(mockTasks);
});
it('dovrebbe fare optimistic update del signal immediatamente', () => {
service.updateStatus('1', 'done');
// Signal aggiornato prima della risposta HTTP
expect(service.tasks().find(t => t.id === '1')?.status).toBe('done');
httpMock.expectOne('/api/tasks/1').flush({...mockTasks[0], status: 'done'});
});
});
describe('Computed Signals', () => {
it('completedTasks dovrebbe filtrare solo i task con status done', () => {
service.loadTasks();
httpMock.expectOne('/api/tasks').flush(mockTasks);
expect(service.completedTasks()).toHaveLength(1);
expect(service.completedTasks()[0].id).toBe('2');
});
it('completionRate dovrebbe calcolare la percentuale corretta', () => {
service.loadTasks();
httpMock.expectOne('/api/tasks').flush(mockTasks);
expect(service.completionRate()).toBe(50);
});
});
});
극작가와 함께하는 E2E 테스트
엔드투엔드 테스트를 위해 Cursor는 하나의 극작가 시나리오를 생성하는 데 탁월합니다. 사용자 흐름의 자연어 설명:
프롬프트: E2E 테스트 극작가
Genera test Playwright E2E per il flusso "Creazione e completamento di un Task".
Scenario:
1. L'utente apre la dashboard (/)
2. Clicca sul pulsante "Nuovo Task"
3. Compila il form: titolo "Test E2E Task", priorità "high", nessuna data scadenza
4. Clicca "Salva"
5. Verifica che il nuovo task appaia nella lista con status "todo"
6. Clicca sull'icona "segna come completato" sul task appena creato
7. Verifica che lo status diventi "done" e che il task appaia nella sezione completati
8. Verifica che completionRate mostri un valore > 0%
Usa page object pattern. Mock il backend con Playwright apiRoutes.
Aggiungi accessibility check con axe-core su ogni schermata.
// e2e/task-flow.spec.ts - Generato da Cursor
import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';
test.describe('Task Creation and Completion Flow', () => {
test.beforeEach(async ({ page }) => {
// Mock API routes
await page.route('/api/tasks', async (route) => {
if (route.request().method() === 'GET') {
await route.fulfill({ json: [] });
} else if (route.request().method() === 'POST') {
const body = route.request().postDataJSON();
await route.fulfill({
json: { id: 'test-1', ...body, status: 'todo', createdAt: new Date().toISOString() }
});
}
});
await page.route('/api/tasks/test-1', async (route) => {
await route.fulfill({ json: { id: 'test-1', status: 'done' } });
});
});
test('dovrebbe creare un task e marcarlo come completato', async ({ page }) => {
await page.goto('/');
// Accessibility check sulla homepage
const a11yResults = await new AxeBuilder({ page }).analyze();
expect(a11yResults.violations).toEqual([]);
// Crea nuovo task
await page.click('[data-testid="new-task-btn"]');
await page.fill('[data-testid="task-title-input"]', 'Test E2E Task');
await page.selectOption('[data-testid="task-priority-select"]', 'high');
await page.click('[data-testid="task-form-submit"]');
// Verifica task in lista
const taskCard = page.locator('[data-testid="task-card-test-1"]');
await expect(taskCard).toBeVisible();
await expect(taskCard.locator('[data-testid="task-status"]')).toHaveText('todo');
// Completa il task
await taskCard.locator('[data-testid="complete-task-btn"]').click();
// Verifica aggiornamento status
await expect(taskCard.locator('[data-testid="task-status"]')).toHaveText('done');
const rate = page.locator('[data-testid="completion-rate"]');
await expect(rate).not.toHaveText('0%');
});
});
6단계 - 리팩토링 패턴 레거시
기존 코드베이스가 있고 Angular 코드를 마이그레이션하는 팀에서 가장 자주 사용되는 사용 사례 중 하나
레거시(NgModules 사용, @Input()/@Output(),
*ngIf/*ngFor) 현대적인 패턴으로. 커서는 이것에 탁월합니다.
일종의 체계적인 리팩토링이다.
프롬프트: 독립형 및 신호로 마이그레이션
Esegui la migrazione del componente @legacy-user-profile.component.ts a:
1. Standalone component (rimuovi dal NgModule)
2. Sostituisci @Input() con input() signal
3. Sostituisci @Output() EventEmitter con output()
4. Converti il template da *ngIf/*ngFor a @if/@for
5. Aggiungi ChangeDetectionStrategy.OnPush
6. Se usa ngModel, converti a reactive form con FormControl tipizzato
7. Aggiorna lo spec file per riflettere i cambiamenti
Dopo ogni cambiamento spiega il ragionamento e i benefici di performance.
대규모 마이그레이션을 위한 계획 모드를 사용한 리팩토링
대규모 마이그레이션(전체 모듈 또는 애플리케이션)의 경우 이전에 계획 모드를 사용하십시오. 에이전트 모드. 이를 통해 커서가 변경하기 전에 계획을 검토할 수 있습니다. 되돌릴 수 없음:
프롬프트: 모듈 마이그레이션 계획 모드
[Attiva Plan Mode con Ctrl+Shift+P → "Plan Mode ON"]
Analizza il modulo UserModule (@src/app/modules/user/) e crea un piano dettagliato
per migrarlo a standalone components con signals. Il modulo ha:
- UserModule.ts (NgModule principale)
- 4 componenti: UserListComponent, UserCardComponent, UserDetailComponent, UserEditComponent
- 2 servizi: UserService, UserPreferencesService
- 1 guard: UserAuthGuard
Per ogni file:
1. Lista le modifiche necessarie
2. Identifica le dipendenze da aggiornare
3. Stima il rischio (Low/Medium/High) con motivazione
4. Suggerisci l'ordine di migrazione per minimizzare il rischio
NON apportare modifiche ancora - solo il piano.
7단계 - 지원 성능 최적화
성능은 커서가 변화를 가져올 수 있는 영역 중 하나입니다. 올바른 질문을 하는 방법을 알고 있습니다. AI가 모든 문제를 자동으로 식별하지는 않습니다. 성능: 해결 중인 문제에 대한 구체적인 맥락을 바탕으로 이를 안내해야 합니다.
번들 분석 및 코드 분할
프롬프트: 번들 분석 및 지연 로딩
Analizza @app.routes.ts e @app.config.ts. Ho eseguito "ng build --stats-json" e
il bundle principale e di 850KB (troppo grande).
Fai queste ottimizzazioni:
1. Converti tutte le route in lazy-loaded routes (usa loadComponent per standalone)
2. Aggiungi PreloadStrategy intelligente: PreloadAllModules per route principali,
nessun preload per route admin/settings raramente visitate
3. Identifica import heavy nel bundle principale da spostare nei chunk lazy
4. Aggiungi SplitChunksPlugin config personalizzata nel angular.json per
separare vendor chunks (rxjs, angular/core separati)
5. Configura budget nel angular.json: warning a 500KB, error a 1MB
// app.routes.ts - Ottimizzato da Cursor con 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),
// Non preloadare: accesso raro
data: { preload: false },
title: 'Impostazioni - Task Manager'
},
{
path: '**',
loadComponent: () =>
import('./shared/components/not-found/not-found.component').then(m => m.NotFoundComponent)
}
];
OnPush 및 신호: 핵심 웹 바이탈
커서는 불필요한 재렌더링과 오류를 유발하는 구성 요소를 식별하는 데 도움이 될 수 있습니다.
그들을로 변환 ChangeDetectionStrategy.OnPush:
프롬프트: 감사 변경 감지
Analizza tutti i componenti in @src/app/features/tasks/ e identifica quelli che:
1. NON usano ChangeDetectionStrategy.OnPush (aggiungi OnPush a tutti)
2. Hanno @Input() che potrebbero diventare input() signals (converti)
3. Usano getters nel template che potrebbero causare re-render (converti a computed())
4. Usano async pipe su Observable (considera toSignal() per semplificare)
Per ogni modifica mostra il codice prima e dopo con spiegazione del beneficio.
8단계 - 커서를 사용하여 생성된 CI/CD 파이프라인
모든 전문 프로젝트의 마지막 단계는 배포 자동화입니다. 커서는 캐싱 전략을 포함하여 완전하고 최적화된 GitHub Actions 파이프라인을 생성합니다. 병렬 테스트 및 분기 기반 조건부 배포.
프롬프트: GitHub Actions 파이프라인 완료
Crea una pipeline GitHub Actions completa per questo progetto Angular 19 con:
WORKFLOW CI (.github/workflows/ci.yml):
- Trigger: push su feature/*, pull_request verso main e develop
- Jobs paralleli: lint, unit-tests, build
- Cache node_modules con chiave basata su package-lock.json
- Unit test con Jest + coverage report (soglia minima: 80%)
- Upload coverage a Codecov
- Build production con --stats-json
- Comment sul PR con bundle size comparison vs base branch
WORKFLOW CD (.github/workflows/cd.yml):
- Trigger: push su main (dopo CI passata)
- Deploy staging su push develop
- Deploy production su push main con approval manuale
- Deploy su Firebase Hosting (usa secrets: FIREBASE_TOKEN)
- Smoke test post-deploy: verifica che / risponda 200 e che il bundle sia < 1MB
- Notifica Slack in caso di fallimento
Usa Node.js 22, npm ci per installazione deterministica.
# .github/workflows/ci.yml - Generato da Cursor
name: CI
on:
push:
branches: ['feature/**', 'fix/**']
pull_request:
branches: [main, develop]
concurrency:
group: ${{ github.workflow }}-${{ 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: ${{ 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
- uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
사례 연구: 아이디어부터 배포까지 "실시간 알림" 기능
우리가 본 모든 것을 통합하기 위해 전문 개발자가 어떻게 하는지 살펴보겠습니다. 커서를 사용하여 기능의 전체 수명주기를 완료합니다. 기능: 알림 추가 작업이 할당되거나 상태가 변경될 때 실시간으로.
이 사례 연구는 AI가 잘못된 경우를 포함하여 실제 흐름을 보여줍니다. 이를 수정하는 방법은 실제 작업 흐름의 일부이기 때문입니다.
1단계 - 계획 모드: 기능 아키텍처
프롬프트 계획 모드
[Plan Mode ON]
Voglio aggiungere notifiche in tempo reale usando WebSocket (Socket.io) per questi eventi:
- task_assigned: quando un task viene assegnato all'utente corrente
- task_status_changed: quando cambia lo stato di un task dell'utente
- task_due_soon: 24h prima della scadenza di un task
Crea un piano architetturale che includa:
1. WebSocket service (con gestione reconnect automatico)
2. NotificationCenter component (slide-in panel)
3. NotificationBadge component (icona navbar con counter)
4. Integration con TaskService esistente
5. Persistenza notifiche non lette in localStorage
6. Testing strategy
Considera: SSR (WebSocket non disponibile lato server),
performance (niente memory leak), accessibilità (screen reader per notifiche live).
계획 모드는 생성/수정할 각 파일이 포함된 구조화된 문서를 생성합니다. 그들과 위험 사이의 의존성. 검토 후 실행을 진행합니다.
2단계 - 에이전트 모드: 구현
// notification.service.ts - Generato dopo approvazione del piano
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() {
// Carica notifiche salvate da localStorage (solo browser)
if (this.platform.isBrowser) {
this._loadPersistedNotifications();
this._initWebSocket();
}
// Persisti automaticamente quando cambiano
effect(() => {
const notifications = this._notifications();
this.platform.setLocalStorage(
'notifications',
JSON.stringify(notifications.slice(0, 50)) // Mantieni 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),
id: crypto.randomUUID(),
timestamp: new Date(),
read: false
};
this._notifications.update(current => [notification, ...current]);
};
this.socket.onclose = () => {
// Reconnect automatico con backoff esponenziale
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 {
// JSON malformato - ignora
}
}
}
ngOnDestroy(): void {
this.socket?.close();
if (this.reconnectTimer) clearTimeout(this.reconnectTimer);
}
}
3단계 - 커서로 버그 식별: SSR 및 WebSocket
검토 중에 Cursor는 잠재적인 문제를 보고합니다. crypto.randomUUID()
일부 SSR 환경에서는 사용할 수 없습니다. 채팅을 사용하여 문제를 해결하세요.
프롬프트: SSR 버그 수정
Ho notato che crypto.randomUUID() potrebbe causare problemi in ambienti SSR o
browser molto vecchi. Nel NotificationService, sostituisci crypto.randomUUID()
con una funzione generaId() che:
1. Usa crypto.randomUUID() se disponibile
2. Fallback su una combinazione di Date.now() + Math.random() per compatibilità
Aggiungi un commento che spiega il perchè del fallback.
4단계 - 테스트 및 PR 검토
프롬프트: PR 및 테스트 준비
La feature notifiche e completa. Aiutami a prepararla per la code review:
1. Genera test unit per NotificationService (includi test per:
- Caricamento notifiche persisted al bootstrap
- markAsRead() e markAllAsRead()
- Comportamento quando platform.isBrowser e false - verifica no WebSocket inizializzato)
2. Controlla il codice che abbiamo scritto per:
- Memory leak (WebSocket, timers non cleanup)
- Problemi di accessibilità nel NotificationCenter template
- Immutabilita (nessun array.push() o mutazione diretta)
- Typing TypeScript (nessun any)
3. Scrivi un CHANGELOG entry per questa feature
Rispondi solo se trovi problemi reali - non citare cose già corrette.
Angular 개발자를 위한 팁과 요령
몇 달 동안 Cursor를 Angular와 함께 집중적으로 사용한 결과 가장 효과적인 패턴은 다음과 같습니다. 전문 개발자가 첫날부터 채택해야 하는 것입니다.
1. 프로젝트 질문에는 @codebase를 사용하세요
"X를 어떻게 할 수 있나요?"라고 묻기 전에 다음을 사용하세요. @codebase 사람들을 이해시키려고
프로젝트의 컨텍스트에 커서를 놓으십시오. 답변의 차이는 상당합니다.
프롬프트 패턴: 코드베이스 컨텍스트
// MENO EFFICACE
"Come aggiungo la paginazione ai task?"
// PIU EFFICACE
"@codebase Guardando TaskListComponent e TaskService,
come aggiungo la paginazione lato server (page + pageSize params sulla GET /api/tasks)
usando i pattern signals e il servizio HTTP già presenti nel progetto?"
2. "검토 및 비평" 프롬프트
Cursor에 제공하고 제품에 대한 비판적인 검토를 요청할 수 있는 가장 유용한 프롬프트 중 하나입니다. 방금 작성한 코드에서 찾고자 하는 문제 유형을 지정합니다.
프롬프트: 전문적인 코드 검토
Rivedi @task.service.ts come senior Angular developer con focus su:
- Performance: computed() non necessari, effect() che potrebbero causare loop,
signal updates che triggherano re-render inutili
- Memory: subscriptions non unsubscribed, timers non cleared,
reference circolari nei signals
- Sicurezza: XSS in template, injection nei parametri HTTP
- Best practices Angular 2025: c'è qualcosa di deprecato?
Dai SOLO feedback concreto con code snippet. Salta gli elogi.
3. 수동이 아닌 커서로 문서화
프롬프트: JSDoc 및 README 생성
Per ogni metodo pubblico in @notification.service.ts aggiungi JSDoc con:
- @description: cosa fa il metodo
- @param: tipizzazione e scopo di ogni parametro
- @returns: cosa ritorna e in che condizioni
- @throws: se il metodo può sollevare errori e in quali condizioni
- @example: un esempio d'uso conciso
Poi genera un README.md per la feature notifications in
src/app/features/notifications/ che documenti il NotificationService
per un nuovo developer del team.
4. 장기 작업을 위한 백그라운드 에이전트
Cursor 2.0 백그라운드 에이전트는 다음과 같이 시간이 많이 소요되는 작업에 이상적입니다. 전체 코드베이스를 분석하거나 수십 개의 구성 요소에 대한 테스트를 생성합니다. 에이전트가 작동하는 동안 계속해서 병렬로 개발할 수 있습니다.
프롬프트: 테스트 적용을 위한 백그라운드 에이전트
[Background Agent]
Analizza tutti i componenti in src/app/features/ che hanno copertura test inferiore
all'80% (controlla i file .spec.ts esistenti o crea test dove mancano).
Per ogni componente con coverage insufficiente:
1. Identifica i casi non coperti (branch, funzioni pubbliche, casi di errore)
2. Scrivi i test mancanti
3. Verifica che npm test passi dopo ogni aggiunta
Lavora in ordine di priorità: prima i componenti con 0% coverage,
poi quelli sotto il 50%, poi quelli tra 50% e 80%.
Notificami quando hai finito con un riepilogo delle coperture raggiunte.
5. 자동 품질을 위한 커서 후크
모든 파일 수정에 대해 자동 검사를 수행하도록 커서 후크 구성 각도. 이렇게 하면 Lint 및 테스트를 수동으로 실행해야 한다는 것을 기억할 필요가 없습니다.
// .cursor/hooks/post-edit.sh
#!/bin/bash
# Eseguito automaticamente dopo ogni salvataggio di file Angular
CHANGED_FILE="$1"
# Lint solo il file modificato (veloce)
if [[ "$CHANGED_FILE" == *.ts ]]; then
npx eslint "$CHANGED_FILE" --fix
fi
# Type check incrementale
if [[ "$CHANGED_FILE" == *.ts ]]; then
npx tsc --noEmit --incremental 2>&1 | head -20
fi
실제 생산성 지표
타당한 질문은 다음과 같습니다. "커서를 사용하면 실제로 얼마나 많은 시간을 절약할 수 있나요?". 기반 전문적인 Angular 프로젝트를 위해 Cursor를 채택한 팀의 문서화된 경험에 대해, 구체적인 측정값은 다음과 같습니다.
벤치마크: 커서가 있거나 없는 Angular 프로젝트
| 활동 | 커서 없이 | 커서 포함 | 저금 |
|---|---|---|---|
| 부트스트랩 프로젝트(CLI + 구성 Jest/ESLint/Prettier) | 45~60분 | 5~10분 | ~85% |
| 완전한 기능 생성(모델 + 서비스 + 4개 구성 요소 + 라우팅) | 3~4시간 | 30~45분 | ~80% |
| 단위 테스트 작성(80% 적용 범위) | 서비스당 2시간 | 20~30분 | ~75% |
| 레거시 구성요소를 독립형 + 신호로 마이그레이션 | 30~45분 | 5~10분 | ~80% |
| CI/CD GitHub 작업 설정 | 2~3시간 | 20~30분 | ~85% |
| 복잡한 버그 디버깅 | 1~2시간 | 20~40분 | ~60% |
이 숫자는 시간을 나타낸다는 점에 유의하는 것이 중요합니다. 코드 생산, 건축 사상의 시대가 아닙니다. 커서는 코드의 기계적인 작성을 가속화합니다. 인간의 전문 지식이 필요한 높은 수준의 결정에 더 많은 시간을 할애합니다.
커서가 충분하지 않을 때
커서는 전문 지식을 대체하는 것이 아니라 생산성을 높이는 도구입니다. 있다 AI가 Angular 컨텍스트에서 한계를 보여주는 상황:
- 전략적 아키텍처 결정: 커서가 옵션을 제안할 수 있으며, 그러나 올바른 상태 관리 전략의 선택(신호 대 NgRx 대 Akita) 이는 본인만이 알고 있는 비즈니스 요인에 따라 다릅니다.
- 고급 성능 디버깅: 메모리 누수로 인한 식별 클로저에서 effect()로 또는 신호 간 순환 재렌더링에 대한 이해가 필요합니다. Angular의 변경 감지 깊이.
- 복잡한 라이브러리와의 통합: 커서는 Angular를 잘 알고 있고, 그러나 매우 특정한 타사 라이브러리에 대한 지식이 제한적일 수 있습니다. 최근 업데이트되었습니다.
- 보안 검토: 그것 없이 생성된 코드를 맹목적으로 신뢰하지 마십시오 안전 검토. 커서는 미묘한 취약점을 유발할 수 있습니다. 인증 관리 및 입력 삭제와 같은 영역에서.
Cursor 및 Angular에서 피해야 할 안티패턴
안티 패턴 1: 코드를 읽지 않고 수락
커서를 사용할 때 가장 큰 위험은 AI에 너무 의존하게 된다는 점입니다. 생성된 코드를 이해하지 못한 채 수락합니다. 이로 인해 일관되지 않은 코드베이스가 발생합니다. 디버깅하기 어려운 버그와 자신의 코드를 이해하지 못하는 개발자.
경험 법칙: 코드가 왜 필요한지 동료에게 설명할 수 없는 경우 생성된 것이 하는 일을 수행하므로 이해할 때까지 받아들이지 마십시오. 커서를 사용하여 이해를 대체하는 것이 아니라 가속화하십시오.
안티 패턴 2: 복잡한 문제에 대한 모호한 프롬프트
// PROMPT VAGO - risultato mediocre
"La lista task non si aggiorna dopo aver modificato uno status"
// PROMPT SPECIFICO - risultato accurato
"@task-list.component.ts @task.service.ts
Quando chiamo updateStatus() nel TaskService, il signal _tasks viene aggiornato
(ho verificato con un debugger che il valore cambia), ma TaskListComponent NON
mostra il cambiamento. Il componente usa OnPush. Ho verificato che l'input
[tasks] viene passato da un componente padre con async pipe.
Il problema potrebbe essere nella reference immutability?"
안티 패턴 3: 반대 규칙
서로 모순되는 규칙이 있는 경우(예를 들어 한 규칙에는 "신호 사용"이라고 되어 있고 다른 하나는 "상태에 BehaviorSubject를 사용하십시오"라고 말하면 커서는 일관되지 않은 코드를 생성합니다. 규칙을 정기적으로 감사하여 충돌을 제거하고 업데이트하세요. 코드베이스를 마이그레이션하면 더 이상 사용되지 않습니다.
안티 패턴 4: 컨텍스트 창 무시
커서에는 컨텍스트 제한이 있습니다. 대화가 너무 길면 메시지를 보내세요. 오래된 것들은 "잊혀졌습니다". 몇 시간 동안 지속되는 복잡한 작업의 경우 여는 것이 좋습니다. 끝없는 세션을 계속하기보다는 새로운 주제별 대화를 나누세요. 효과적인 프롬프트를 다른 이름으로 저장 커서 추억 재사용합니다.
결론: 2026년의 Angular 개발자 워크플로
We come to the end of this article and the entire series on Cursor IDE. 워크플로 우리가 구축한 것은 전문적인 Angular 개발의 최첨단 기술을 나타냅니다. 2026년: 접근 방식 AI 기반이지만 개발자가 제어함, 지능이 있는 곳 인공 기술은 인간의 판단을 대체하지 않고 각 단계를 가속화합니다.
전체 워크플로를 요약하려면 다음을 수행하세요.
- 규칙 구성: 구체적인 규칙을 만드는 데 시간을 투자하세요. 당신의 스택을 위해. 이것이 가장 큰 승수입니다. 잘 작성된 모든 규칙은 향상됩니다. AI와의 미래의 모든 상호작용.
- 에이전트 모드 이전의 계획 모드: 복잡한 기능이나 마이그레이션의 경우 실행하기 전에 항상 계획을 세우십시오. 수정된 계획은 잘못된 구현보다 빠릅니다.
- 부트스트래핑을 위한 에이전트 모드: AI가 생성을 처리하도록 하세요. 구조, 구성 요소 및 구성. 당신의 시간은 상용구에 비해 너무 많은 가치가 있습니다.
- AI로 테스트하기: 커서로 테스트 생성, 엣지 케이스 검토, 추가 AI가 고려하지 않은 경우. 4분의 1의 시간 안에 80%의 보장을 받으세요.
- 지원 리팩토링: 체계적인 패턴 마이그레이션을 위해 커서를 사용하세요 현대적(신호, 독립형, 새로운 구문). 백그라운드 에이전트를 사용하여 전체 모듈로 확장합니다.
- CI/CD 생성됨: YAML 파이프라인을 직접 작성하지 마세요. 요구 사항 설명 커서가 정확하고 최적화된 구성을 생성하도록 합니다.
이 워크플로를 수용하는 개발자는 덜 전문적이지 않습니다. 기하급수적으로 생산성이 향상됨. 전문성은 여전히 기본입니다. 생성된 코드를 평가하고, 아키텍처 결정을 내리고, 품질을 유지합니다. 프로젝트의. 커서는 레벨러가 아닙니다. 이미 좋은 사람의 능력을 확장합니다.
커서 IDE 및 AI 네이티브 개발 시리즈 요약
| # | Articolo | 주요 초점 |
|---|---|---|
| 1 | 커서 IDE: 전체 가이드 | 개요, 설치, 핵심 기능 |
| 2 | 커서 규칙 | 프로젝트를 위한 AI 설정 |
| 3 | 에이전트 모드 | 명령으로 코드베이스 변경 |
| 4 | 계획 모드 및 백그라운드 에이전트 | 계획 및 병렬성 |
| 5 | 커서 후크 | 워크플로우 자동화 |
| 6 | MCP 및 커서 | 데이터베이스 및 API에 대한 연결 |
| 7 | 커서 AI를 사용한 디버깅 | 3배 더 빠른 버그 수정 |
| 8 | 커서 vs 윈드서핑 vs 부조종사 | 2026년 장비 비교 |
| 9 | 현재 위치 - 전문적인 Angular 워크플로 | 설정부터 배포까지 완벽한 사례 연구 |
탐색할 관련 시리즈
- 최신 Angular(ID 224-233): 독립형 신호에 대해 자세히 알아보기 전용 가이드가 포함된 구성 요소, SSR 및 최신 Angular 기능을 소개합니다.
- MCP 및 커서(ID 64-77): 모델 컨텍스트 프로토콜(Model Context Protocol)을 살펴보세요. Cursor를 데이터베이스, API 및 외부 도구에 연결하는 세부 정보입니다.
- 바이브코딩: 개발자가 AI를 사용하여 프로토타입을 제작하는 방법을 알아보세요. Claude Code, 멀티 에이전트 시스템 및 AI 코드 테스트를 통해 아이디어를 빠르게 얻을 수 있습니다.
전체 시리즈를 팔로우해 주셔서 감사합니다. 질문이나 의견이 있거나 공유하고 싶은 사항이 있으면 Cursor를 사용하여 Angular 워크플로에 댓글을 작성하세요. 당신의 기여가 도움이 됩니다 전체 이탈리아 개발자 커뮤니티를 위해 이 가이드를 개선하세요.







