| name | development-standards |
| description | Normes de développement frontend et backend pour la mise en oeuvre de projet Angular/Fastapi |
When to Use This Skill
- Creation of new projects
- Code implementation
- Development of high-performance web services and microservices
- Creation of asynchronous applications
- Implementation of structured and tested API projects
🎓 Development Standards
Framework Technologies
| Layer | Technology | Version | Features |
|---|
| Frontend | Angular | 21 | Signals, Signal Forms, Zoneless, Standalone |
| Backend | FastAPI | 0.136.0 | Async/Await, Pydantic v2 |
| UI Framework | Bootstrap | 5.3.8 | Responsive, Accessible |
| Icons | Bootstrap Icons | 1.13.1 | SVG Icons |
| Python Runtime | Python | 3.14 | Asynchronous |
| Node Runtime | Node.js | 18+ | ES2021 |
| Deployment | Docker | Multi-stage | Single Container SPA |
📘 ANGULAR 21 STANDARDS
Les SPA Angular 21 doivent suivre les normes suivantes pour garantir la maintenabilité, les performances et la scalabilité.
1. Principes Fondamentaux
Angular 21 apporte des changements majeurs:
- ✅ Signaux (réactivité granulaire)
- ✅ Signal Forms (formulaires réactifs simplifiés)
- ✅ Zoneless (sans NgZone, performances meilleures)
- ✅ Standalone Components (pas de modules)
- ❌ Directives avec
* (dépréciées: *ngIf, *ngFor, *ngSwitch)
- ❌ Two-way Binding avec
[(ngModel)] (déprécié, utiliser des signaux et événements)
- ❌ Change Detection avec Zones (déprécié, utiliser des signaux et computed)
- ❌ Reactive Forms avec
FormGroup (déprécié, utiliser form et FormField de Signal Forms)
- ✅ Control Flow (syntaxe nouvelle:
@if, @for, @switch)
- ✅ HTML Format recommandé avec fichier séparé:
- ✅ CSS Format recommandé avec fichier séparé:
2. Types de Composants
Tous les composants doivent avoir des fichiers séparés pour template et style:
app/features/user/
├── user-list/
│ ├── user-list.component.ts ← Code TypeScript
│ ├── user-list.component.html ← Template HTML
│ └── user-list.component.css ← Styles CSS
3. Architecture des Dossiers
frontend/src/app/
├── core/ # Singleton services, guards, interceptors
│ ├── services/
│ │ ├── auth.service.ts # Authentication
│ │ ├── api.service.ts # HTTP API calls
│ │ ├── theme.service.ts # Theme management
│ │ └── ...
│ ├── guards/
│ │ └── auth.guard.ts # Route protection
│ ├── interceptors/
│ │ └── auth.interceptor.ts # Add JWT tokens
│ ├── models/
│ │ ├── auth.models.ts
│ │ ├── user.models.ts
│ │ └── ...
│ └── constants/
│ └── app.constants.ts
│
├── features/ # Feature modules (lazy loaded)
│ ├── auth/
│ │ ├── login/
│ │ │ ├── login.component.ts
│ │ │ ├── login.component.html
│ │ │ └── login.component.css
│ │ └── ...
│ ├── dashboard/
│ │ ├── dashboard.component.ts
│ │ ├── dashboard.component.html
│ │ └── dashboard.component.css
│ └── ...
│
├── shared/ # Reusable components, pipes, directives
│ ├── components/
│ │ ├── header/
│ │ ├── layout/
│ │ └── ...
│ ├── pipes/
│ │ └── custom.pipe.ts
│ └── directives/
│ └── custom.directive.ts
│
├── app.config.ts # Angular configuration
├── app.routes.ts # Route definitions
├── app.component.ts # Root component
└── main.ts # Application entry point
🐍 FASTAPI STANDARDS
Les projets FastAPI doivent suivre les normes suivantes pour garantir la maintenabilité, les performances et la scalabilité.
1. Principes Fondamentaux
- ✅ Async/Await (toutes les fonctions de route sont asynchrones)
- ✅ Pydantic v2 (validation des données avec les nouveaux modèles)
- ✅ Gestion d'erreurs avec HTTPException
- ✅ Logging structuré (pas de print())
- ✅ Type hints complets (sur toutes les fonctions)
- ✅ Docstrings complètes (format Google style)
- ✅ Configuration via variables d'environnement (pas de secrets hardcodés)
- ✅ Structure de projet modulaire (services, modèles, routes séparés)
📋 CONVENTIONS COMMUNES
1. Noms de Fichiers
# Angular
my-component.component.ts # Composant
my-component.component.html # Template
my-component.component.css # Styles
my.service.ts # Service
my.pipe.ts # Pipe
my.directive.ts # Directive
my.guard.ts # Guard
# FastAPI
user_service.py # Service
user_models.py # Modèles Pydantic
user_routes.py # Routes
config.py # Configuration
exceptions.py # Exceptions personnalisées
2. Conventions de Nommage
const MAX_RETRY = 3;
let currentUser: User | null;
function getUserById(id: number): User;
class UserService { }
interface IUser { }
type AuthResponse = { ... };
enum Status { ACTIVE, INACTIVE }
data-testid="user-form"
aria-label="Close modal"
(click)="handleClick()"
(keydown.enter)="submitForm()"
[attr.aria-expanded]="isOpen()"
MAX_RETRIES = 3
current_user = None
def get_user_by_id(user_id: int):
class UserService:
async def fetch_data():
3. Gestion d'Erreurs
try {
const user = await this.userService.getUser(id).toPromise();
this.selectedUser.set(user);
} catch (error) {
logger.error("Failed to load user", error);
this.errorMessage.set("Failed to load user. Please try again.");
}
try:
user = await self.db.get_user(user_id)
if not user:
raise NotFoundException("User", user_id)
return user
except Exception as exc:
logger.error(f"Error fetching user {user_id}: {exc}")
raise HTTPException(
status_code=500,
detail="Internal server error"
)
🔧 PRE-COMMIT CONFIGURATION & LINTING
Tous les changements doivent respecter la configuration définie dans .pre-commit-config.yaml.
Hooks Disponibles
Le fichier .pre-commit-config.yaml configure les outils suivants:
1. Ruff - Python Linting & Formatting
Ruff remplace Black, Flake8, isort et autres (outils Python).
ruff check backend/ --fix
ruff format backend/
[tool.ruff]
line-length = 100
target-version = "py314"
[tool.ruff.lint]
select = ["E", "F", "W", "I", "B", "C4", "UP"]
ignore = ["E501"]
Utilisé pour:
- Vérification PEP 8
- Formatage du code Python
- Tri des imports
- Réduction de la complexité
2. Python Typing Update - Type Hints Modernization
Met à jour la syntaxe des type hints Python aux standards modernes.
pre-commit run --hook-stage manual python-typing-update --all-files
Exemples de mise à jour:
from typing import Optional, List
def get_users() -> Optional[List[str]]:
pass
def get_users() -> list[str] | None:
pass
3. Prettier - Frontend Formatting
Formate HTML, JSON, YAML, et Markdown.
npm run prettier
cd frontend && npx prettier --write "src/**/*.{ts,html,scss}"
{
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"trailingComma": "es5",
"arrowParens": "avoid"
}
4. Codespell - Spell Checking
Vérifie l'orthographe et détecte les erreurs courantes.
codespell
codespell --write-changes
skip = ./.git,*.json,*.csv,.devcontainer,.vscode
ignore-words-list = te
5. Standard Pre-commit Hooks
Hooks fournis par pre-commit pour validations basiques:
check-json
check-yaml
check-toml
check-added-large-files
end-of-file-fixer
trailing-whitespace
mixed-line-ending
Assurez-vous que les fichiers se terminent par un saut de ligne.
Supprimez les espaces de fin de ligne.
Normalisez les fins de ligne.
6. yamllint - YAML Validation
Valide la structure YAML selon les standards.
yamllint .
extends: default
rules:
line-length: disable
indentation:
spaces: 2
Exécution Manuelle des Hooks
prek run --all-files
prek run ruff-format --all-files
prek run prettier --all-files
prek install
prek autoupdate
git commit --no-verify
Workflow Recommandé
Avant chaque commit:
cd backend && ruff format . && cd ..
cd frontend && npm run prettier && cd ..
prek run --all-files
prek run --all-files
cd backend && python -m pytest && cd ..
cd frontend && npm run test && cd ..
git add .
git commit -m "feat(scope): description"
Configuration IDE pour Auto-Format
VS Code - .vscode/settings.json:
{
"[python]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.codeActionsOnSave": {
"source.fixAll": "explicit",
"source.organizeImports": "explicit"
}
},
"[typescript]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[html]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[yaml]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
Erreurs Courantes et Fixes
Erreur: "Line too long"
user_data = UserService.get_all_active_users_with_pending_transactions_and_notifications()
user_data = UserService.get_all_active_users_with_pending_transactions_and_notifications()
Erreur: "Import sorting"
import os
from typing import List
import sys
from app.models import User
import os
import sys
from typing import List
from app.models import User
Erreur: "Type hints missing"
def process_data(data):
return data.strip()
def process_data(data: str) -> str:
"""Process user input.
Args:
data: Input string to process.
Returns:
str: Processed string.
"""
return data.strip()
⚠️ ERREURS COURANTES À ÉVITER
Frontend - Angular
❌ Ne pas utiliiser zone.js:
export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
]
};
✅ Utiliser Angular en mode zoneless:
export const appConfig: ApplicationConfig = {
providers: [
provideZonelessChangeDetection()
]
};
❌ Utiliser les anciennes directives:
<div *ngIf="isVisible">Content</div>
<div *ngFor="let item of items">{{ item }}</div>
✅ Utiliser le nouveau control flow:
@if (isVisible) {
<div>Content</div>
}
@for (item of items; track item.id) {
<div>{{ item }}</div>
}
❌ Ne pas utiliser les signaux:
export class MyComponent {
isLoading = false;
items: Item[] = [];
}
✅ Utiliser les signaux:
export class MyComponent {
isLoading = signal(false);
items = signal<Item[]>([]);
itemCount = computed(
() =>
this.items().length,
);
}
❌ Inliner trop de code HTML/CSS:
@Component({
selector: 'app-complex',
template: `<div>... 150 lignes ...</div>`,
styles: [`... 100 lignes CSS ...`]
})
✅ Utiliser des fichiers séparés:
@Component({
selector: 'app-complex',
templateUrl: './complex.component.html',
styleUrls: ['./complex.component.scss']
})
❌ Utiliser any type:
function processData(data: any): any {
return data.transform();
}
✅ Utiliser des types spécifiques:
interface DataModel {
id: number;
name: string;
}
function processData(data: DataModel): string {
return data.name.toUpperCase();
}
❌ Oublier de se désabonner (RxJS):
export class MyComponent implements OnInit {
ngOnInit() {
this.service.data$.subscribe((data) => {
this.items = data;
});
}
}
✅ Utiliser takeUntilDestroyed ou signaux:
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
export class MyComponent {
private destroyRef = inject(DestroyRef);
constructor(private service: Service) {
this.service.data$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((data) => {
this.items = data;
});
}
}
Backend - FastAPI
❌ Typing manquant:
def get_user(user_id):
return db.get_user(user_id)
✅ Type hints complets:
async def get_user(
user_id: int,
db: AsyncSession = Depends(get_db)
) -> UserResponse:
"""Get user by ID.
**❌ Typing déprécié:**
```python# WRONG - Old typing syntax
from typing import List, Optional
✅ Typing moderne:
def get_users() -> list[UserResponse] | None:
...
❌ Backtrace dans le retour client
try:
function()
except Exception as exc:
return f"Error {exc}"
❌ Endpoints non-asynchrones:
@app.get("/users")
def get_users():
users = db.query(User).all()
return users
✅ Endpoints asynchrones:
@app.get("/users")
async def get_users(
db: AsyncSession = Depends(get_db)
) -> List[UserResponse]:
"""Get all users."""
users = await db.get_all_users()
return users
❌ Utiliser print() pour logs:
@app.get("/data")
async def get_data():
print("User requested data")
return {"status": "ok"}
✅ Utiliser logging:
import logging
logger = logging.getLogger(__name__)
@app.get("/data")
async def get_data() -> dict:
"""Get data."""
logger.info("User requested data")
return {"status": "ok"}
❌ Pas de type hints:
def create_user(user_data):
return UserService.create(user_data)
✅ Type hints complets:
async def create_user(
user_data: UserCreate,
db: AsyncSession = Depends(get_db)
) -> UserResponse:
"""Create new user.
Args:
user_data: User creation request.
db: Database session.
Returns:
UserResponse: Created user.
Raises:
HTTPException: If user already exists.
"""
user = await db.create_user(user_data)
return user
❌ Gestion d'erreurs manquante:
@app.get("/items/{item_id}")
async def get_item(item_id: int):
item = await db.get_item(item_id)
return item
✅ Gestion d'erreurs appropriée:
@app.get("/items/{item_id}", response_model=ItemResponse)
async def get_item(
item_id: int,
db: AsyncSession = Depends(get_db)
) -> ItemResponse:
"""Get item by ID.
Args:
item_id: Item unique ID.
db: Database session.
Returns:
ItemResponse: Item data.
Raises:
HTTPException: If item not found.
"""
item = await db.get_item(item_id)
if not item:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Item {item_id} not found"
)
return item
❌ Hardcoder la configuration:
DATABASE_URL = "postgresql://user:password@localhost/db"
SECRET_KEY = "my-secret-key"
ADMIN_PASSWORD = "fixed-password"
✅ Utiliser les variables d'environnement:
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
database_url: str
secret_key: str
admin_password: str
class Config:
env_file = ".env"
settings = Settings()
❌ Pas de validation Pydantic:
@app.post("/users")
async def create_user(data: dict):
user = await db.create(data)
return user
✅ Validation avec Pydantic:
from pydantic import BaseModel, EmailStr, Field
class UserCreate(BaseModel):
username: str = Field(
...,
min_length=3,
max_length=50,
description="Username 3-50 chars"
)
email: EmailStr
password: str = Field(
...,
min_length=8,
description="Password min 8 chars"
)
@app.post("/users", response_model=UserResponse)
async def create_user(
user_data: UserCreate,
db: AsyncSession = Depends(get_db)
) -> UserResponse:
"""Create user with validation."""
user = await db.create_user(user_data)
return user
🔗 Ressources Complètes
Frontend - Angular 21
UI & Styling
Backend - FastAPI
DevOps & Qualité
Development Tools
📞 Support & Contribution
Pour toute question concernant les normes de développement:
- Consulter ce fichier SKILL.md
- Vérifier les exemples dans le code existant
- Consulter la documentation officielle des frameworks
- Demander aide à l'équipe senior
Contributions aux normes
Pour proposer des modifications aux normes:
- Créer une branche
docs/standards-update
- Mettre à jour le fichier SKILL.md
- Créer une Pull Request avec justification
- Attendre l'approbation de l'équipe
📝 Historique des versions
| Version | Date | Changements |
|---|
| 1.2.0 | 2026-03-13 | Ajout section documentation |
| 1.1.0 | 2026-03-07 | Ajout section pre-commit & erreurs courantes |
| 1.0.0 | 2026-03-07 | Version initiale avec Angular 21 & FastAPI |
Dernière mise à jour: 7 Mars 2026
Statut: Production Ready ✅
Mainteneurs: Development Team