プロフェッショナルなワークフロー: 設定からデプロイまでのカーソルを使用した Angular プロジェクト
カーソル、そのルール、エージェント モード、プラン モード、フック、MCP プロトコルについて学びました。 今こそすべてを 1 つにまとめるべき時です 本物のプロフェッショナルなワークフロー。この記事 シリーズの最終回と運用ケーススタディ: Cursor を使用して完全な Angular プロジェクトを構築します プロジェクトの初期化から運用展開まで、あらゆる段階で AI が副操縦します。
これはベスト プラクティスを集めた抽象的なものではありません。各セクションには実際のコマンドとプロンプトが表示されます 効果的で具体的な構成と、統合時に専門チームが下す決定 日々の開発プロセスにおけるカーソル。この記事の最後にはプレイブックが記載されています あらゆる Angular プロジェクトで完全かつ複製可能です。
私たちが構築するプロジェクトは 1 つです タスク管理ダッシュボード 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 が次のことを認識できるように設定することです。 コードの最初の行を書く前に、プロジェクトの規則を理解してください。のファイル 適切に構造化されたルールにより、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 - プロフェッショナルなワークフロー: カーソルを使用した Angular プロジェクト | Federico Calò
09 - プロフェッショナルなワークフロー: カーソルを使用した Angular プロジェクト | 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 - プロフェッショナルなワークフロー: カーソルを使用した Angular プロジェクト | Federico Calò
09 - プロフェッショナルなワークフロー: カーソルを使用した Angular プロジェクト | 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 - プロフェッショナルなワークフロー: カーソルを使用した Angular プロジェクト | Federico Calò
09 - プロフェッショナルなワークフロー: カーソルを使用した Angular プロジェクト | 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 - プロフェッショナルなワークフロー: カーソルを使用した Angular プロジェクト | Federico Calò
09 - プロフェッショナルなワークフロー: カーソルを使用した Angular プロジェクト | 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 何百行もの巨大なものです。
その結果、Cursor は、最も関連性の高い命令に優先順位を付けることができなくなります。
現在のコンテキスト。特定の glob パターンを持つ個別のファイルを使用する: i のルール
コンポーネントは次の場合にのみアクティブになります *.component.ts、コンテキストを維持する
焦点を絞った最も正確な答え。
コンポーネントのルール: angular-components.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 - エージェント モードでのプロジェクトのセットアップ
ルールを構成したら、プロジェクトを作成します。手動で実行する代わりに 各コマンドと各ファイルの作成では、エージェント モードを使用してブートストラップ フェーズ全体を委任します。 これは Cursor の最も強力な使用例の 1 つです。高レベルの指示を与えてそのままにしておきます。 エージェントがすべての操作手順を実行します。
カーソルを開き、プロジェクトの新しいフォルダーを作成し、エージェント モードを起動します。 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 コンポーネントを生成する方法を詳しく見てみましょう。プロンプトを出した後
above, let's examine the output for 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 プロパティについて
e 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 とカーソルによる増分水分補給
Angular 19 ポート 追加の水分補給 安定版では、これを可能にする機能 ページの表示またはインタラクティブになる部分のみをハイドレートし、 大幅に初期のJavaScript。 SSR を正しく構成することは、最も重要な領域の 1 つです 微妙な誤差が生じる可能性があります。ここではカーソルが特に役立ちます。
このプロンプトを使用して、増分ハイドレーションと適切な管理を備えた 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 で最も一般的なエラーの 1 つは、データが 2 回ロードされることです。
レンダリング中にサーバー側で実行され、ハイドレーション後にクライアント側で再度実行されます。カーソルで追加できる
自動的に 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);
});
});
});
Playwright との E2E テスト
エンドツーエンドのテストでは、Cursor は 1 つのシナリオから Playwright シナリオを生成することに優れています。 ユーザー フローの自然言語による説明:
プロンプト: 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 コードを移行するチームで最も頻繁に使用されるユースケースの 1 つ
レガシー (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 - パフォーマンス最適化支援
パフォーマンスは Cursor が違いを生むことができる領域の 1 つですが、それには次のことが必要です。 正しい質問の仕方を知っている。 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 とシグナル: コア Web バイタル
カーソルは、不必要な再レンダリングを引き起こすコンポーネントを特定するのに役立ちます。
それらをに変換します 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 アクション パイプラインの完了
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/
ケーススタディ: アイデアから導入までの「リアルタイム通知」機能
これまで見てきたすべてを統合するために、プロの開発者がどのように行うかを見てみましょう。 Cursor を使用して機能のライフサイクル全体を完了します。機能: 通知を追加する タスクが割り当てられたとき、または状態が変化したとき、リアルタイムで監視されます。
このケーススタディでは、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 開発者のためのヒントとコツ
Angular で Cursor を数か月間集中的に使用した結果、最も効果的なパターンを次に示します。 プロの開発者は初日からこれを採用する必要があります。
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.「レビューと批評」のプロンプト
カーソルを与えて、その文書の批判的なレビューを求めることができる最も便利なプロンプトの 1 つ 見つけたい問題の種類を指定して、作成したばかりのコードを入力します。
プロンプト: 特殊なコードレビュー
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
実際の生産性の指標
正当な質問は次のとおりです。 「Cursor を使用すると実際にどれくらいの時間を節約できますか?」。ベース プロフェッショナルな Angular プロジェクトに Cursor を採用したチームの文書化された経験について、 具体的な測定値は次のとおりです。
ベンチマーク: カーソルがある場合とない場合の Angular プロジェクト
| 活動 | カーソルなし | カーソルあり | 貯蓄 |
|---|---|---|---|
| ブートストラップ プロジェクト (CLI + 構成 Jest/ESLint/Prettier) | 45~60分 | 5~10分 | ~85% |
| 完全な機能生成 (モデル + サービス + 4 コンポーネント + ルーティング) | 3~4時間 | 30~45分 | ~80% |
| 単体テストの作成 (カバレッジ 80%) | 1サービスあたり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、秋田) それはあなただけが知っているビジネス要因によって異なります。
- 高度なパフォーマンスのデバッグ: 原因となったメモリ リークを特定します クロージャからeffect()への移行、またはシグナル間の周期的再レンダリングについては理解する必要があります。 Angular の変更検出の深さ。
- 複雑なライブラリとの統合: カーソルは Angular をよく知っており、 ただし、非常に特殊なサードパーティ ライブラリについての知識が限られている場合や、 最近更新されました。
- セキュリティレビュー: それなしで生成されたコードを盲目的に信頼しないでください 安全性のレビュー。特にカーソルは微妙な脆弱性を引き起こす可能性があります 認証管理や入力のサニタイズなどの分野で。
Cursor と Angular で回避すべきアンチパターン
アンチパターン 1: コードを読まずに受け入れる
Cursor を使用する際の最大のリスクは、AI に依存してしまうことです。 生成されたコードを理解せずに受け入れます。これにより、コードベースの一貫性が失われ、 デバッグが難しいバグや、自分のコードを理解していない開発者。
経験則: 同僚にコードを使用する理由を説明できない場合は、 generated はその機能を実行します。理解するまでは受け入れないでください。カーソルを使用して、 理解に代わるものではなく、加速します。
アンチパターン 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 を使用する」と言っています)、Cursor は一貫性のないコードを生成します。 ルールを定期的に監査して競合を除去し、それらを更新します。 コードベースを移行すると廃止されます。
アンチパターン 4: コンテキスト ウィンドウを無視する
カーソルにはコンテキスト制限があります。非常に長い会話がある場合は、メッセージ 古いものは「忘れられた」ものです。何時間もかかる複雑なタスクの場合は、オープンすることをお勧めします。 終わりのないセッションを続けるのではなく、新しいテーマに沿った会話をすることができます。 効果的なプロンプトを次の名前で保存します カーソルメモリー それらを再利用するために。
結論: 2026 年の Angular 開発者のワークフロー
この記事と Cursor IDE に関するシリーズ全体はこれで終わりです。ワークフロー 私たちが構築したものは、プロフェッショナルな Angular 開発の最先端を表しています。 2026 年: アプローチ AI ネイティブだが開発者が制御、ここで知性 人工テクノロジーは、人間の判断を置き換えることなく、各段階を加速します。
完全なワークフローを要約すると、次のようになります。
- ルールの設定: 特定のルールの作成に時間を投資します。 あなたのスタックのために。これが最大の乗数です。よく書かれたルールはすべて改善されます。 AI との将来のあらゆるやり取り。
- エージェント モードの前にプラン モード: 複雑な機能または移行の場合、 実行する前に必ず計画を立ててください。修正された計画は、間違った実装よりも早いです。
- ブートストラップ用のエージェント モード:AIに作成を任せる 構造、コンポーネント、構成。あなたの時間は定型文としては価値がありすぎます。
- AIによるテスト: カーソルを使用してテストを生成し、エッジケースを確認し、追加します AIが考慮しなかったケース。 4 分の 1 の時間で 80% のカバー率が得られます。
- 支援付きリファクタリング: 体系的なパターンの移行にはカーソルを使用します 最新 (シグナル、スタンドアロン、新しい構文)。バックグラウンド エージェントを使用してモジュール全体に拡張します。
- 生成されたCI/CD: YAML パイプラインを手動で作成しないでください。要件を説明する そして、Cursor が正しく最適化された構成を生成できるようにします。
このワークフローを採用する開発者は、専門家でなくなるわけではありません。 飛躍的に生産性が向上。専門知識は依然として基礎的なものである 生成されたコードを評価し、アーキテクチャ上の決定を行い、品質を維持します プロジェクトの。カーソルは平準化するものではありません。すでに優れている人の能力を拡張します。
カーソル IDE および AI ネイティブ開発シリーズの概要
| # | アイテム | 主な焦点 |
|---|---|---|
| 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): モデル コンテキスト プロトコルを探索する Cursor をデータベース、API、外部ツールに接続するための詳細。
- バイブコーディング: 開発者が AI を使用してプロトタイプを作成する方法を学びます クロード コード、マルチ エージェント システム、AI コード テストを使用して、アイデアを迅速に作成します。
シリーズ全体をフォローしていただきありがとうございます。ご質問、フィードバック、または共有したい場合は Cursor を使用した Angular ワークフローについては、コメントに記入してください。あなたの貢献が役に立ちます イタリアの開発者コミュニティ全体のためにこれらのガイドを改善します。







