@neikyun/ciel 6.14.0 → 6.14.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/assets/.claude/hooks/check-dispatch-gate.sh +14 -41
  2. package/assets/.claude/hooks/memory-engine.py +66 -5
  3. package/assets/.claude/hooks/pre-tool-write.sh +17 -52
  4. package/assets/.claude/hooks/session-start.sh +15 -128
  5. package/assets/.claude/hooks/stop.sh +10 -85
  6. package/assets/.claude/hooks/user-prompt-submit.sh +17 -110
  7. package/assets/.claude/rules/api-design.md +23 -0
  8. package/assets/.claude/rules/backend.md +22 -0
  9. package/assets/.claude/rules/cicd-pipeline.md +23 -0
  10. package/assets/.claude/rules/containers.md +23 -0
  11. package/assets/.claude/rules/database-design.md +22 -0
  12. package/assets/.claude/rules/environments.md +27 -0
  13. package/assets/.claude/rules/frontend.md +25 -0
  14. package/assets/.claude/rules/github.md +22 -0
  15. package/assets/.claude/rules/logging.md +23 -0
  16. package/assets/.claude/rules/monitoring.md +25 -0
  17. package/assets/.claude/rules/research.md +20 -0
  18. package/assets/.claude/settings.json +2 -58
  19. package/assets/.claude/skills/agile/SKILL.md +42 -0
  20. package/assets/.claude/skills/alerting/SKILL.md +55 -0
  21. package/assets/.claude/skills/api-design/SKILL.md +46 -0
  22. package/assets/.claude/skills/appsec/SKILL.md +43 -0
  23. package/assets/.claude/skills/architecture/SKILL.md +74 -0
  24. package/assets/.claude/skills/backend/SKILL.md +41 -0
  25. package/assets/.claude/skills/backup-recovery/SKILL.md +42 -0
  26. package/assets/.claude/skills/caching/SKILL.md +44 -0
  27. package/assets/.claude/skills/cdn/SKILL.md +42 -0
  28. package/assets/.claude/skills/chaos/SKILL.md +41 -0
  29. package/assets/.claude/skills/cicd-pipeline/SKILL.md +56 -0
  30. package/assets/.claude/skills/ciel/SKILL.md +14 -0
  31. package/assets/.claude/skills/ciel/reference.md +171 -0
  32. package/assets/.claude/skills/cloud/SKILL.md +42 -0
  33. package/assets/.claude/skills/code-quality/SKILL.md +42 -0
  34. package/assets/.claude/skills/code-review/SKILL.md +41 -0
  35. package/assets/.claude/skills/communication/SKILL.md +42 -0
  36. package/assets/.claude/skills/containers/SKILL.md +42 -0
  37. package/assets/.claude/skills/cqrs/SKILL.md +41 -0
  38. package/assets/.claude/skills/crypto/SKILL.md +46 -0
  39. package/assets/.claude/skills/data-engineering/SKILL.md +42 -0
  40. package/assets/.claude/skills/database-design/SKILL.md +46 -0
  41. package/assets/.claude/skills/ddd/SKILL.md +45 -0
  42. package/assets/.claude/skills/deployment-strategies/SKILL.md +51 -0
  43. package/assets/.claude/skills/desktop/SKILL.md +42 -0
  44. package/assets/.claude/skills/devsecops/SKILL.md +43 -0
  45. package/assets/.claude/skills/environments/SKILL.md +66 -0
  46. package/assets/.claude/skills/event-driven/SKILL.md +46 -0
  47. package/assets/.claude/skills/frontend/SKILL.md +41 -0
  48. package/assets/.claude/skills/functional/SKILL.md +42 -0
  49. package/assets/.claude/skills/github/SKILL.md +61 -0
  50. package/assets/.claude/skills/high-availability/SKILL.md +42 -0
  51. package/assets/.claude/skills/iac/SKILL.md +46 -0
  52. package/assets/.claude/skills/logging/SKILL.md +46 -0
  53. package/assets/.claude/skills/ml-engineering/SKILL.md +42 -0
  54. package/assets/.claude/skills/mobile/SKILL.md +42 -0
  55. package/assets/.claude/skills/monitoring/SKILL.md +54 -0
  56. package/assets/.claude/skills/networking/SKILL.md +42 -0
  57. package/assets/.claude/skills/nosql/SKILL.md +41 -0
  58. package/assets/.claude/skills/oop-solid/SKILL.md +42 -0
  59. package/assets/.claude/skills/performance/SKILL.md +41 -0
  60. package/assets/.claude/skills/reactive/SKILL.md +42 -0
  61. package/assets/.claude/skills/release-management/SKILL.md +51 -0
  62. package/assets/.claude/skills/research/SKILL.md +69 -0
  63. package/assets/.claude/skills/resilience/SKILL.md +41 -0
  64. package/assets/.claude/skills/serverless/SKILL.md +42 -0
  65. package/assets/.claude/skills/servers/SKILL.md +41 -0
  66. package/assets/.claude/skills/sql/SKILL.md +45 -0
  67. package/assets/.claude/skills/supply-chain/SKILL.md +41 -0
  68. package/assets/.claude/skills/system-design/SKILL.md +91 -0
  69. package/assets/.claude/skills/tech-leadership/SKILL.md +46 -0
  70. package/assets/.claude/skills/testing/SKILL.md +41 -0
  71. package/assets/.claude/skills/tracing/SKILL.md +36 -0
  72. package/assets/CLAUDE.md +31 -122
  73. package/assets/commands/{ciel-memory-bootstrap.md → ciel-memory-init.md} +3 -3
  74. package/assets/commands/ciel-memory.md +210 -0
  75. package/assets/platforms/opencode/.opencode/commands/{ciel-memory-bootstrap.md → ciel-memory-init.md} +3 -3
  76. package/assets/skills/ciel/SKILL.md +8 -97
  77. package/bin/ciel.js +1 -1
  78. package/dist/cli/check.d.ts.map +1 -1
  79. package/dist/cli/check.js +5 -11
  80. package/dist/cli/check.js.map +1 -1
  81. package/dist/cli/claude.d.ts.map +1 -1
  82. package/dist/cli/claude.js +42 -4
  83. package/dist/cli/claude.js.map +1 -1
  84. package/dist/cli/doctor.d.ts +16 -0
  85. package/dist/cli/doctor.d.ts.map +1 -0
  86. package/dist/cli/doctor.js +168 -0
  87. package/dist/cli/doctor.js.map +1 -0
  88. package/dist/cli/index.js +76 -0
  89. package/dist/cli/index.js.map +1 -1
  90. package/dist/cli/init.d.ts.map +1 -1
  91. package/dist/cli/init.js +23 -4
  92. package/dist/cli/init.js.map +1 -1
  93. package/dist/cli/memory.d.ts +18 -0
  94. package/dist/cli/memory.d.ts.map +1 -0
  95. package/dist/cli/memory.js +304 -0
  96. package/dist/cli/memory.js.map +1 -0
  97. package/dist/cli/opencode.js +1 -1
  98. package/dist/cli/opencode.js.map +1 -1
  99. package/package.json +2 -2
  100. /package/assets/{rules → .claude/rules}/security.md +0 -0
  101. /package/assets/{rules → .claude/rules}/testing.md +0 -0
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: logging
3
+ description: "Logging — structured JSON, correlation ID, PII scrubbing, centralized aggregation, log levels as signal. À charger quand on configure les logs."
4
+ ---
5
+
6
+ # Logging
7
+
8
+ **Principe premier :** Les logs ne sont pas pour toi — ils sont pour le "toi du futur" qui debug une erreur à 3h du matin sans contexte. Un log qui dit "Error occurred" est pire que pas de log — il donne l'illusion d'information. Chaque log doit répondre à : quoi, quand, où, qui, et pourquoi c'est arrivé. Le format est JSON structuré, pas du texte libre — parce que les logs seront parsés par des machines (Loki, ELK, Datadog) bien avant d'être lus par des humains.
9
+
10
+ ## Checklist
11
+ - [ ] Logs structurés JSON — pas de `console.log("texte libre " + variable)`
12
+ - [ ] Correlation ID (trace ID) injecté et transmis à travers tous les services
13
+ - [ ] Niveaux de log respectés : ERROR (action requise), WARN (attention), INFO (normal), DEBUG (détail)
14
+ - [ ] Stack trace + contexte (userId, orderId, params) dans chaque ERROR
15
+ - [ ] PII/secret scrubbing : jamais de password, token, carte bancaire, email dans les logs
16
+ - [ ] Centralisation : tous les logs vers un endpoint unique (Loki/ELK/CloudWatch)
17
+ - [ ] Rétention configurée : hot 7j, warm 30j, cold 1 an
18
+
19
+ ## Anti-patterns
20
+ ### Log texte libre
21
+ **Ce qu'on voit :** `console.log("User " + userId + " logged in at " + Date.now())`. Concaténation de strings.
22
+ **Pourquoi c'est dangereux :** impossible à parser automatiquement. Pas de champ structuré. Recherche et filtrage impossibles sans regex fragiles. Si le format change légèrement, tous les dashboards cassent.
23
+ **Faire plutôt :** `logger.info({ event: "user_login", userId, timestamp }, "User logged in")`. JSON structuré. Champs typés. Requêtable.
24
+
25
+ ### Pas de correlation ID
26
+ **Ce qu'on voit :** chaque service logue avec son propre ID. Impossible de suivre une requête à travers 3 microservices.
27
+ **Pourquoi c'est dangereux :** debug en microservices = ouvrir 3 terminaux, chercher manuellement des timestamps qui coïncident. Une requête lente = mystère complet.
28
+ **Faire plutôt :** correlation ID généré à l'entrée (API Gateway). Transmis dans chaque header HTTP. Logué dans chaque service. Une recherche = une requête = tous les logs.
29
+
30
+ ### Données sensibles dans les logs
31
+ **Ce qu'on voit :** `logger.error("Payment failed", { cardNumber, cvv, userId })`.
32
+ **Pourquoi c'est dangereux :** PCI-DSS violé. Données bancaires dans les logs. En cas de fuite des logs, toutes les cartes compromises. Les logs sont souvent moins protégés que la DB.
33
+ **Faire plutôt :** `logger.error("Payment failed", { paymentId, errorCode, userId })`. Jamais de PII ou secret. Scrub automatisé en cas de doute.
34
+
35
+ ## Patterns
36
+ ### Structured JSON logging
37
+ **Quand :** toute application.
38
+ **Comment :** chaque log = `{timestamp, level, message, service, correlationId, ...context}`. Parse, filtre, indexe par Loki/ELK. Requêtable : `{.level = "ERROR"} | json | ...`
39
+
40
+ ### Centralized aggregation
41
+ **Quand :** plus d'un service.
42
+ **Comment :** tous les logs → stdout (K8s/Docker) → Promtail (parse, label) → Loki (stocke) → Grafana (requete LogQL). Un seul endroit pour chercher. LogQL : `{service="api", level="error"} |= "payment" | json`. Depuis Grafana, lien direct : log → trace ID → Tempo → span exact.
43
+
44
+ ### Debug flow Grafana (metrics → logs → traces)
45
+ **Quand :** incident en production.
46
+ **Comment :** (1) Grafana dashboard : métrique RED rouge → clic sur le point → (2) "Explore logs" → LogQL filtré par temps + service → (3) extraire le trace ID du log → (4) Tempo : trace complète avec tous les spans. Sans intégration, ces 3 outils sont séparés. Avec Grafana, ils sont liés.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: ml-engineering
3
+ description: "ML Engineering — pipelines ML, feature stores, model serving, drift detection, MLOps, experiment tracking. A charger quand on met en production des modeles ML."
4
+ ---
5
+
6
+ # ML Engineering
7
+
8
+ **Principe premier :** Le ML engineering n'est pas "entrainer un modele avec le meilleur score" — c'est mettre un modele en production et garantir qu'il reste performant dans le temps. La metrique qui compte n'est pas l'accuracy sur le dataset de test (qui est un instantane du passe) — c'est la performance en production sur les donnees de demain. Un modele est un programme qui se degrade passivement : le monde change, les distributions derivent, et un modele a 98% de precision aujourd'hui peut tomber a 72% dans 6 mois sans que personne ne le sache. La difference entre un notebook Jupyter et un systeme ML de production, c'est le monitoring, le versioning, et la capacite a re-entrainer.
9
+
10
+ ## Checklist
11
+ - [ ] Les donnees sont versionnees (DVC, LakeFS, Delta Lake) — pas de `dataset_v3_final_FINAL.csv`
12
+ - [ ] Les experiences sont trackees (MLflow, W&B, ClearML) avec hyperparametres, code version, dataset version
13
+ - [ ] Le feature store est la source unique de verite pour les features — pas de features calculees differemment en train et en inference
14
+ - [ ] Le serving est monitorise : latence P95, taux d'erreur, distribution des predictions
15
+ - [ ] Le data drift ET le concept drift sont monitorises — alerter quand la distribution change
16
+ - [ ] Le pipeline d'entrainement est reproductible (DAG, conteneurise, versionne)
17
+ - [ ] Le rollback de modele est aussi simple que le rollback de code (model registry avec versioning)
18
+
19
+ ## Anti-patterns
20
+ ### Notebook → production
21
+ **Ce qu'on voit :** le data scientist donne son notebook "il marche sur mon laptop". L'ingenieur le copie-colle dans un endpoint. 2000 lignes de code non structure.
22
+ **Pourquoi c'est dangereux :** un notebook n'est pas un programme — c'est un journal d'exploration. Pas de gestion d'erreur, pas de typage, pas de tests, pas de reproductibilite (execution ordonnee non garantie). Les imports sont eparpilles, les variables persistent entre cellules, le code est impossible a maintenir.
23
+ **Faire plutot :** le notebook est un outil d'exploration. Le code de production est dans des modules Python standards, versionnes, testes. Le data scientist et le ML engineer travaillent ensemble sur la transition notebook → module. Le notebook documente l'intention, le module implemente la production.
24
+
25
+ ### Features train/serve inconsistantes
26
+ **Ce qu'on voit :** les features sont calculees en Python (pandas) pour l'entrainement, et en Go/Java dans le serving. Implementation differente → comportement different → modele qui performe mal en production sans raison apparente.
27
+ **Pourquoi c'est dangereux :** c'est le bug le plus pernicieux en ML. Les metriques d'entrainement sont bonnes, les tests passent, mais le modele est mauvais en production. La cause est quasi impossible a debugger sans comparer les implementations feature par feature.
28
+ **Faire plutot :** feature store central. Les memes features, calculees par le meme code, servent l'entrainement ET l'inference. Si le calcul change, le feature store versionne. Zero implementation divergente.
29
+
30
+ ### Drift = surprise
31
+ **Ce qu'on voit :** pas de monitoring du drift. Le modele se degrade lentement. 6 mois plus tard, un utilisateur remarque que les predictions sont mauvaises.
32
+ **Pourquoi c'est dangereux :** la degradation est silencieuse et graduelle. Le modele ne crash pas — il devient juste de plus en plus mauvais. Les decisions basees sur ces predictions deviennent de plus en plus mauvaises. Le MTTD (mean time to detect) est de 6 mois.
33
+ **Faire plutot :** monitoring continu de la distribution des features en production vs distribution d'entrainement (data drift). Monitoring des predictions (concept drift : relation feature → cible qui change). Alerter quand la divergence depasse un seuil. Re-entrainement automatise ou manuel selon la criticite.
34
+
35
+ ## Patterns
36
+ ### Model registry
37
+ **Quand :** plusieurs modeles en production ou re-entrainements frequents.
38
+ **Comment :** MLflow Model Registry, Seldon, ou Sagemaker Model Registry. Chaque modele a : version, metriques, dataset d'origine, artefact, statut (staging/production/archived). Promotion staging → production via CI/CD. Rollback = pointer vers la version precedente en un clic.
39
+
40
+ ### Feature store
41
+ **Quand :** features reutilisees entre plusieurs modeles ou entre train/serving.
42
+ **Comment :** Feast, Tecton, ou solution interne. Les features sont definies une fois, calculees offline (batch) et servies online (low latency). Le feature store garantit la consistance entre train et serve. Chaque feature est versionnee et documentee.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: mobile
3
+ description: "Mobile — iOS/Android/React Native/Flutter, offline-first, batterie, store review, push notifications. A charger quand on developpe une application mobile."
4
+ ---
5
+
6
+ # Mobile
7
+
8
+ **Principe premier :** Le mobile n'est pas "un petit ecran" — c'est un environnement hostile. Reseau instable (tunnel → metro → edge → 3G), batterie limitee, stockage restreint, OS qui peut killer l'app a tout moment. Si ton app ne fonctionne pas dans un tunnel avec 1 barre de 3G et 10% de batterie, elle ne fonctionne pas. Le store (App Store, Play Store) est ton canal de distribution mais aussi ton gatekeeper — chaque release est une revue humaine qui peut etre rejetee. Le mobile recompense l'optimisme offline et le pessimisme reseau : suppose toujours que le reseau est lent, cher, et hostile.
9
+
10
+ ## Checklist
11
+ - [ ] Offline-first : l'app fonctionne sans reseau — donnees en cache local, actions en file d'attente
12
+ - [ ] Les images sont lazy-loadees et resizees (pas de 4K telecharge sur un ecran 400px de large)
13
+ - [ ] La batterie est respectee : pas de polling every 5s, pas de wake lock permanent, pas de GPS continu
14
+ - [ ] Le state est preserve a travers les kills d'OS (serialisation automatique du state critique)
15
+ - [ ] Les crashs sont reportes (Crashlytics, Sentry) — pas de "ca crash sur le telephone de Julie"
16
+ - [ ] Les updates sont gerees : forced update si API incompatible, optional update sinon
17
+ - [ ] Le stockage local a un TTL et une limite de taille — pas de cache infini qui remplit le telephone
18
+
19
+ ## Anti-patterns
20
+ ### Mobile = site web en webview
21
+ **Ce qu'on voit :** une webview qui charge le site responsive. Publie sur les stores. "Ca marche sur mobile."
22
+ **Pourquoi c'est dangereux :** zero integration native. Pas de push notifications, pas de stockage offline, pas de gestures natives, pas de transition fluide. Les utilisateurs le sentent immediatement et desinstallent. Les stores peuvent rejeter si l'app n'apporte rien par rapport au site.
23
+ **Faire plutot :** si le contenu est statique → PWA (plus leger, pas besoin de store). Si besoin natif (push, camera, offline) → app native ou React Native/Flutter avec vrais composants natifs.
24
+
25
+ ### Optimiste sur le reseau
26
+ **Ce qu'on voit :** l'app suppose que le reseau est disponible et rapide. Pas de cache, pas de queue offline, pas de gestion d'erreur reseau. L'app affiche un spinner blanc des que le reseau est lent.
27
+ **Pourquoi c'est dangereux :** le reseau mobile est le pire reseau de tous les clients. L'utilisateur est dans un ascenseur, un metro, une cave, une campagne. Si l'app ne fonctionne pas offline, elle est inutilisable 30% du temps. L'utilisateur ouvre l'app concurrente.
28
+ **Faire plutot :** cache local (SQLite, Realm, WatermelonDB). Sync en arriere-plan quand le reseau est disponible. UI qui montre les donnees en cache immediatement, puis rafraichit. Indicateur "donnees de X minutes" plutot qu'un spinner.
29
+
30
+ ### Release = pari
31
+ **Ce qu'on voit :** soumission sur le store sans test de recette. Rejet pour violation de guideline. 3 jours de delai. Corrections en catastrophe.
32
+ **Pourquoi c'est dangereux :** le store review est un processus humain, lent, et imprevisible. Un rejet decale la release de 3-7 jours. Les utilisateurs attendent, les bugs critiques restent en production.
33
+ **Faire plutot :** pre-release checklist (guidelines store, screenshots, permissions documentees). TestFlight/Internal Testing pour valider le binaire avant soumission. Soumission en debut de semaine pour maximiser les chances de review rapide.
34
+
35
+ ## Patterns
36
+ ### Offline-first avec sync queue
37
+ **Quand :** app qui modifie des donnees (notes, taches, commandes).
38
+ **Comment :** ecriture locale immediate → queue de synchronisation → synchro background quand online. Resolution de conflits : last-write-wins pour donnees simples, merge pour donnees complexes. UI qui montre l'etat de synchro (sync, synced, error).
39
+
40
+ ### Gradual rollout sur stores
41
+ **Quand :** release avec risque (refonte, nouvelle fonctionnalite).
42
+ **Comment :** Play Store : staged rollout (10% → 50% → 100% avec possibilite de halt). App Store : phased release sur 7 jours. Monitoring des crashs et des ratings par version. Rollback en arretant le rollout (pas besoin de nouvelle soumission).
@@ -0,0 +1,54 @@
1
+ ---
2
+ name: monitoring
3
+ description: "Monitoring — RED/USE metrics, SLI/SLO/SLA comme contrats, dashboards comme outils de debugging, alerting fatigue. À charger quand on met en place du monitoring."
4
+ ---
5
+
6
+ # Monitoring
7
+
8
+ **Principe premier :** Le monitoring n'est pas "avoir des dashboards" — c'est pouvoir répondre à deux questions en < 30 secondes : "est-ce que le système fonctionne ?" et "si non, qu'est-ce qui a changé ?". Si tes dashboards ne répondent pas à ça, ils sont du bruit visuel. La métrique fondamentale n'est pas le nombre de graphiques — c'est le Mean Time To Detect (MTTD). Combien de temps entre le début de l'incident et la première alerte ? Si la réponse est "quand un client ouvre un ticket", ton monitoring a échoué.
9
+
10
+ ## Checklist
11
+ - [ ] RED metrics par service : Rate, Errors, Duration (P50/P95/P99) — collectées via Prometheus, exposées sur `/metrics`
12
+ - [ ] USE metrics par ressource : Utilization, Saturation, Errors — node_exporter/cAdvisor → Prometheus → Grafana
13
+ - [ ] Dashboards, règles Prometheus, et config AlertManager sont dans le repo (monitoring as code) — pas créés à la main dans l'UI Grafana
14
+ - [ ] Dashboards Grafana avec seuils visuels (vert/jaune/rouge) — pas juste des lignes sur un graphique
15
+ - [ ] SLI définis (ce qu'on mesure), SLO documentés (l'objectif), SLA communiqués (la promesse)
16
+ - [ ] Alertes sur les signaux critiques uniquement — pas d'alerte sur "CPU > 70% pendant 30s à 3h du matin"
17
+ - [ ] Runbook associé à chaque alerte — "si cette alerte sonne, voici quoi faire"
18
+
19
+ ## Anti-patterns
20
+ ### Dashboard = décoration
21
+ **Ce qu'on voit :** un écran mural avec 50 graphiques, pas de titre, pas d'échelle, pas de seuil. Personne ne le regarde. Les incidents sont découverts par les utilisateurs.
22
+ **Pourquoi c'est dangereux :** un dashboard sans contexte n'est pas un outil — c'est du bruit. Les anomalies sont noyées dans la masse de données non interprétables. Le MTTD est infini.
23
+ **Faire plutôt :** un dashboard par service. Titre explicite. Description : "Ce dashboard montre la santé du service X. Si ce graphique est rouge, regarder Y." Seuils visuels. Maximum 10 métriques par dashboard. Le dashboard doit permettre de répondre "est-ce que c'est normal ?" en un coup d'œil.
24
+
25
+ ### Alerte sur tout
26
+ **Ce qu'on voit :** 200 alertes configurées. "CPU > 50%", "mémoire > 60%", "disque > 70%". 15 alertes par nuit. L'équipe a muté le canal. Les vraies urgences sont ignorées.
27
+ **Pourquoi c'est dangereux :** l'alert fatigue est réelle. Chaque fausse alerte entraîne la suivante vers l'ignorance. Quand une vraie alerte critique arrive, personne ne la voit parce que tout le monde a appris que "les alertes = du bruit".
28
+ **Faire plutôt :** alerter sur les SYMPTÔMES, pas sur les causes potentielles. "P95 latency > 1s pendant 5 min" (symptôme utilisateur), pas "CPU > 70%" (cause possible). Chaque alerte doit être actionable — si tu ne peux pas écrire le runbook en 3 étapes, ne crée pas l'alerte.
29
+
30
+ ### Monitoring = dashboards Grafana
31
+ **Ce qu'on voit :** tout est dans Grafana. Pas de logs structurés, pas de tracing, pas d'alerting. "On regardera le dashboard si quelqu'un se plaint."
32
+ **Pourquoi c'est dangereux :** le monitoring sans observabilité, c'est regarder le tableau de bord de ta voiture. Tu vois que la vitesse est à 0, mais tu ne sais pas POURQUOI. Les dashboards montrent les symptômes, les logs et traces montrent les causes. L'un sans l'autre = tu sais que c'est cassé, pas pourquoi.
33
+ **Faire plutôt :** monitoring (métriques + dashboards + alertes) + logging (logs structurés JSON + correlation ID) + tracing (OpenTelemetry, traces distribuées). Les trois piliers de l'observabilité.
34
+
35
+ ## Patterns
36
+ ### Prometheus + Grafana (stack standard)
37
+ **Quand :** toute application en production.
38
+ **Comment :** Prometheus scrape les métriques exposées par l'app (`/metrics`). Grafana interroge Prometheus (PromQL) et affiche les dashboards. Pas de solution propriétaire — cette stack est le standard ouvert, toutes les bibliothèques l'implémentent. Chaque service expose ses propres métriques RED, l'infrastructure expose les USE via node_exporter / cAdvisor.
39
+
40
+ ### RED method (services)
41
+ **Quand :** monitoring de tout service (API, worker, etc.).
42
+ **Comment :** Rate (requêtes/s), Errors (taux d'erreur), Duration (P50/P95/P99) via histogram Prometheus. 3 métriques par endpoint. Couvre l'expérience utilisateur. PromQL : `rate(http_requests_total[5m])`, `rate(http_errors_total[5m])`, `histogram_quantile(0.95, rate(http_duration_bucket[5m]))`.
43
+
44
+ ### USE method (ressources)
45
+ **Quand :** monitoring de toute ressource (CPU, RAM, disque, réseau, DB pool).
46
+ **Comment :** Utilization (% utilisé), Saturation (file d'attente), Errors (compteur d'erreurs) via node_exporter. 3 métriques par ressource. Dashboard Grafana avec seuils vert/jaune/rouge. Si Utilization > 80%, si Saturation > 0, si Errors > 0 — investiguer.
47
+
48
+ ### SLO-based alerting
49
+ **Quand :** définir les alertes sans tomber dans l'alert fatigue.
50
+ **Comment :** définir un SLO (ex: "99.9% des requêtes < 500ms sur 30 jours"). L'alerte se déclenche quand le error budget est consommé trop vite (ex: 5% du budget mensuel en 1h). Configurer dans AlertManager via Prometheus rules : `alert: HighErrorBurnRate`, `expr: rate(http_errors_total[1h]) / rate(http_requests_total[1h]) > 0.05`.
51
+
52
+ ### Monitoring as Code (dashboards + rules dans le repo)
53
+ **Quand :** toute équipe de plus d'une personne.
54
+ **Comment :** dashboards Grafana en JSON (Grafonnet pour les générer), règles Prometheus en YAML, config AlertManager en YAML — tout dans `monitoring/` du repo. Déploiement via CI/CD (Terraform, Grafana provisioning API). PR pour chaque changement de dashboard ou alerte. Le monitoring est de l'infrastructure — le même niveau de rigueur que le Terraform de prod.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: networking
3
+ description: "Networking — le reseau comme fondation invisible. DNS, TLS, HTTP/2/3, VPC, firewall, load balancing. A charger quand on configure des connexions ou debug la connectivite."
4
+ ---
5
+
6
+ # Networking
7
+
8
+ **Principe premier :** Le reseau n'est pas "ce qui connecte les machines" — c'est la couche de securite zero. Avant que ton application ne recoive un octet, le reseau a deja pris 100 decisions : routage, filtrage, terminaison TLS, rate limiting. Un reseau bien configure rend 80% des attaques impossibles avant meme qu'elles n'atteignent l'application. Le probleme inverse : un reseau mal configure est invisible jusqu'a l'incident — "pourquoi le service B ne peut pas parler au service C en prod ?" La connectivite n'est jamais acquise — elle est configuree, testee, monitorisee.
9
+
10
+ ## Checklist
11
+ - [ ] DNS est configure avec TTL raisonnable (300s pour APEX, 60s pour failover) — pas de TTL de 86400s
12
+ - [ ] TLS >= 1.2 partout, TLS 1.3 pour les services internes — pas de TLS 1.0/1.1, pas de SSL
13
+ - [ ] Les certificats sont auto-renouveles (LetsEncrypt, cert-manager, ACM) — pas d'expiration surprise
14
+ - [ ] Firewall : seuls les ports necessaires sont ouverts. SSH (22) restreint par IP source
15
+ - [ ] Les VPC/VNET sont isoles par environnement (dev/staging/prod) avec peering explicite
16
+ - [ ] HTTP/2 ou HTTP/3 active — multiplexing, header compression, 0-RTT
17
+ - [ ] Le load balancer a un health check actif (pas juste TCP connect — verifier le endpoint)
18
+
19
+ ## Anti-patterns
20
+ ### "C'est un probleme reseau"
21
+ **Ce qu'on voit :** chaque bug de connexion est blame sur "le reseau". Personne ne debug. Le probleme persiste 3 semaines.
22
+ **Pourquoi c'est dangereux :** le reseau est un bouc emissaire facile parce qu'il est invisible. En realite, la plupart des problemes "reseau" sont des problemes d'application : timeout trop court, DNS cache, certificat expire, mauvais endpoint. Dire "c'est le reseau" sans preuve = arreter de chercher.
23
+ **Faire plutot :** debug methodique : `dig` (DNS), `curl -v` (TLS + HTTP), `traceroute` (routage), `telnet host port` (connectivite brute). Chaque couche se teste independamment. Le probleme est toujours sur UNE couche specifique.
24
+
25
+ ### Firewall = apres coup
26
+ **Ce qu'on voit :** le firewall est configure "quand tout marche" (jamais). Tous les ports sont ouverts "pour pas etre bloque".
27
+ **Pourquoi c'est dangereux :** le firewall est la premiere ligne de defense. Sans regles strictes, une application vulnerable sur un port oublie = acces non autorise. Le firewall interne (entre services) est aussi important que l'externe.
28
+ **Faire plutot :** deny-all par defaut. Ouvrir uniquement les flux documentes. Chaque regle a un commentaire (pourquoi ce port, pour quel service). Revue trimestrielle des regles.
29
+
30
+ ### DNS comme apres-pensee
31
+ **Ce qu'on voit :** TTL = 86400 (24h). Changement de serveur → 24h de propagation. Les utilisateurs voient l'ancienne IP. Ou pire : `CNAME` court-circuite avec un `A` record parce que "c'est plus simple".
32
+ **Pourquoi c'est dangereux :** DNS est le premier maillon de toute connexion. Un TTL trop long empeche le failover rapide. Un mauvais enregistrement = outage total. Le DNS est la fondation — tout repose dessus.
33
+ **Faire plutot :** TTL courts pour les endpoints critiques (60-300s). Records A/AAAA pour la racine, CNAME pour les sous-domaines. Monitoring de resolution DNS depuis plusieurs points geographiques.
34
+
35
+ ## Patterns
36
+ ### Defense en profondeur reseau
37
+ **Quand :** architecture multi-services.
38
+ **Comment :** WAF/CDN (couche 1) → Load Balancer + TLS termination (couche 2) → Network ACL/VPC firewall (couche 3) → Security Group par service (couche 4). Chaque couche suppose que la precedente a echoue. Aucune couche ne fait confiance a la precedente.
39
+
40
+ ### Zero Trust networking
41
+ **Quand :** services distribues, multi-cloud, ou travailleurs distants.
42
+ **Comment :** pas de "reseau interne de confiance". Chaque appel est authentifie (mTLS, JWT, SPIFFE). Le reseau est hostile par defaut — les services ne se font pas plus confiance entre eux qu'a Internet. C'est le principe inverse du "perimetre de securite".
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: nosql
3
+ description: "NoSQL — MongoDB/DynamoDB/Redis, modeling around access patterns, single-table design, hot partition avoidance. À charger quand on choisit ou utilise du NoSQL."
4
+ ---
5
+
6
+ # NoSQL
7
+
8
+ **Principe premier :** NoSQL n'est pas "SQL sans schéma" — c'est un trade-off fondamental : tu échanges la flexibilité des requêtes (tu ne peux pas tout JOINer) contre la scalabilité horizontale (tu peux sharder). Ce trade-off est le SEUL critère valide pour choisir NoSQL. Si tu n'as pas de problème de scale horizontal que SQL ne résout pas, NoSQL est un downgrade, pas une modernisation. Le modeling NoSQL se fait à l'envers du relationnel : tu pars des requêtes (qu'est-ce que je dois lire en une opération ?) et tu construis le modèle autour.
9
+
10
+ ## Checklist
11
+ - [ ] Le choix NoSQL est justifié par le scale horizontal, pas par "c'est plus simple"
12
+ - [ ] Le modèle de données est conçu autour des access patterns (et pas l'inverse)
13
+ - [ ] La partition key a une haute cardinalité et une distribution uniforme
14
+ - [ ] Les index secondaires (GSI) sont justifiés — chaque GSI coûte de l'argent et de la latence
15
+ - [ ] La stratégie de dénormalisation est documentée : quelle donnée est dupliquée, où, pourquoi
16
+ - [ ] Les TTL sont configurés pour les données temporaires — pas de job de nettoyage manuel
17
+
18
+ ## Anti-patterns
19
+ ### Modélisation relationnelle dans NoSQL
20
+ **Ce qu'on voit :** 12 `$lookup` (MongoDB) pour reproduire un JOIN. 50 `GetItem` séquentiels (DynamoDB) parce que les données sont dans des items séparés.
21
+ **Pourquoi c'est dangereux :** NoSQL n'est pas optimisé pour les JOINs. Chaque `$lookup` est un scan coûteux. Chaque `GetItem` est une requête réseau. 50 requêtes séquentielles DynamoDB = 500ms de latence minimum contre 10ms pour un JOIN SQL. Tu paies le prix du NoSQL sans le bénéfice.
22
+ **Faire plutôt :** pre-joindre. Si les données sont lues ensemble, elles sont stockées ensemble (single document/item). Le modèle reflète les patterns d'accès — une requête = un read.
23
+
24
+ ### Hot partition / hot key
25
+ **Ce qu'on voit :** partition key = `status` avec 90% des items à `status = "active"`. Ou pire, partition key = `tenant_id` et un tenant fait 80% du trafic.
26
+ **Pourquoi c'est dangereux :** en NoSQL, les partitions sont l'unité de scale. Une partition chaude = tout le trafic sur un seul shard = throttling (DynamoDB) ou performance dégradée (MongoDB). Le scale horizontal est neutralisé par une mauvaise clé.
27
+ **Faire plutôt :** partition key à haute cardinalité et distribution uniforme. `user_id`, `order_id`, pas de `status` ou `type`. Si un tenant est plus gros, sharder par `tenant_id#entity_id` (composite key).
28
+
29
+ ### Redis comme source de vérité
30
+ **Ce qu'on voit :** toutes les données métier dans Redis. `FLUSHALL` ou reboot = toutes les données perdues. "Mais j'ai configuré la persistence" — qui n'a jamais été testée.
31
+ **Pourquoi c'est dangereux :** Redis est conçu comme un cache/queue/session store en mémoire. La persistence Redis (RDB/AOF) est asynchrone et non garantie. Même avec AOF everysec, tu peux perdre les 2 dernières secondes d'écritures.
32
+ **Faire plutôt :** PostgreSQL/MySQL/DynamoDB pour la source de vérité. Redis pour cache, sessions, rate limiting, queues temporaires. Si Redis est flush, l'app dégrade mais ne perd pas de données métier.
33
+
34
+ ## Patterns
35
+ ### Single-table design (DynamoDB)
36
+ **Quand :** plusieurs types d'entités avec des access patterns différents.
37
+ **Comment :** une table. PK = `TYPE#id`, SK = `RELATION#id`. Les GSI inversent PK/SK pour les autres patterns. Un user et ses orders sont dans la même table, lus en une query. Pas de JOIN.
38
+
39
+ ### TTL index
40
+ **Quand :** données temporaires (sessions, cache, logs éphémères).
41
+ **Comment :** champ `expires_at` en epoch seconds + TTL index. La DB supprime automatiquement. Pas de cron job. Pas de nettoyage manuel. Gratuit (DynamoDB) ou quasi-gratuit.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: oop-solid
3
+ description: "OOP & SOLID — classes, objets, heritage, composition, encapsulation, principes SOLID comme garde-fous. A charger quand on travaille avec des classes."
4
+ ---
5
+
6
+ # OOP & SOLID
7
+
8
+ **Principe premier :** SOLID n'est pas un dogme — c'est un systeme d'alerte precoce. Chaque principe ne te dit pas quoi faire, il te dit QUAND le design est en train de pourrir. Single Responsibility = ta classe a plus d'une raison de changer. Open/Closed = tu modifies du code existant au lieu d'etendre. Liskov = ta sous-classe ne peut pas remplacer la classe mere. Interface Segregation = tes clients dependent d'interfaces qu'ils n'utilisent pas. Dependency Inversion = tes modules de haut niveau dependent des bas niveau. Le but n'est pas un score SOLID parfait — c'est un code qui accepte le changement sans se briser. La composition est par defaut, l'heritage est l'exception.
9
+
10
+ ## Checklist
11
+ - [ ] Chaque classe a une responsabilite unique (SRP) — decrire son job en une phrase sans "et"
12
+ - [ ] Les classes sont ouvertes a l'extension, fermees a la modification (OCP) — nouveau comportement = nouveau code, pas modification
13
+ - [ ] Les sous-classes sont substituables a leur classe mere (LSP) — pas de `if (obj instanceof SpecialCase)`
14
+ - [ ] Les interfaces sont minimales (ISP) — pas d'interface de 15 methodes dont 10 jettent `NotImplementedException`
15
+ - [ ] Les modules haut niveau ne dependent pas des bas niveau (DIP) — les deux dependent d'abstractions
16
+ - [ ] L'heritage est utilise pour "est-un", pas pour reutiliser du code — composition > heritage
17
+ - [ ] Le couplage est reduit : un changement dans une classe ne force pas une cascade de changements
18
+
19
+ ## Anti-patterns
20
+ ### SOLID comme religion
21
+ **Ce qu'on voit :** chaque classe est precedee de `interface IFoo`. Chaque `new` est remplace par une factory + DI container. 50 classes pour afficher "Hello World".
22
+ **Pourquoi c'est dangereux :** SOLID utilise en dogme produit l'inverse de son intention : code rigide, difficile a changer, difficile a comprendre. Une interface pour chaque classe = explosion du nombre de fichiers. DI partout = perdu dans les couches d'indirection.
23
+ **Faire plutot :** appliquer SOLID la ou le changement est PROBABLE. Un composant stable peut violer SOLID — c'est acceptable. Introduire une abstraction quand un deuxieme cas concret apparait (pas avant). SOLID est un outil de diagnostic, pas un objectif de design.
24
+
25
+ ### Heritage deep chain
26
+ **Ce qu'on voit :** `Animal → Mammal → Canine → Dog → Labrador → GoldenLabrador`. Chaque classe ajoute un comportement. Pour comprendre `GoldenLabrador`, il faut lire 6 classes.
27
+ **Pourquoi c'est dangereux :** l'heritage profond cree un couplage vertical. Changer `Animal` affecte toutes les 200 sous-classes. Impossible de comprendre une classe isolement. Le YAGNI frappe fort : la plupart des classes intermediaires ne sont jamais utilisees directement.
28
+ **Faire plutot :** limiter a 1-2 niveaux d'heritage maximum. Composer les comportements (Strategy, Decorator) plutot qu'heriter. Si une classe a plus de 2 ancetres concrets, repenser le design.
29
+
30
+ ### Classe "Manager" / "Utils" / "Helper"
31
+ **Ce qu'on voit :** `UserManager` (3000 lignes), `DateUtils` (150 fonctions statiques), `StringHelper` (tout le monde ajoute des trucs).
32
+ **Pourquoi c'est dangereux :** les noms en -Manager, -Utils, -Helper sont des aveux d'echec de design. Ils ne disent rien sur ce que fait la classe. Ils attirent le code non relie comme un aimant. Une classe qui s'appelle `Manager` n'a pas de responsabilite — elle en a 50.
33
+ **Faire plutot :** nommer les classes par leur responsabilite reelle. `UserRepository`, `UserAuthenticator`, `UserNotificationSender`. Si une classe a plus de 10 methodes publiques, la splitter par responsabilite. Les "utils" sont un signe qu'un concept manque dans le domaine.
34
+
35
+ ## Patterns
36
+ ### Composition over inheritance
37
+ **Quand :** quasi tout le temps.
38
+ **Comment :** au lieu de `class Duck extends Bird extends Animal`, injecter les comportements : `class Duck { constructor(flyBehavior, quackBehavior, swimBehavior) }`. Chaque comportement est interchangeable. Testable independamment. Le duck peut changer de FlyBehavior au runtime.
39
+
40
+ ### Dependency injection par constructeur
41
+ **Quand :** toute classe qui depend d'un service externe (DB, API, file system).
42
+ **Comment :** `constructor(db: Database, logger: Logger)` — les dependances sont explicites. Pas de `new Database()` dans la classe. Pas de singleton global (`Database.getInstance()`). Le test peut injecter un mock/adaptateur. La classe ne sait pas CREER ses dependances, elle les RECOIT.
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: performance
3
+ description: "Performance — mesurer avant d'optimiser, P95 > moyenne, performance budgets, profiling, N+1, slow queries. À charger quand on parle d'optimisation."
4
+ ---
5
+
6
+ # Performance
7
+
8
+ **Principe premier :** "Make it work, make it right, make it fast" — dans cet ordre. La performance est une feature, pas une propriété magique. Comme toute feature, elle a un coût et doit être mesurée. Le piège classique est l'optimisation prématurée : du code complexe et illisible pour gagner 5ms sur un endpoint appelé 10×/jour. La règle d'or : ne jamais optimiser sans avoir mesuré. Le bottleneck réel n'est presque jamais là où on pense. Et la métrique qui compte n'est pas la moyenne — c'est le P95 (ou P99). La moyenne ment parce qu'elle cache les outliers, et ce sont les outliers qui pourrissent l'expérience utilisateur.
9
+
10
+ ## Checklist
11
+ - [ ] Profiling AVANT optimisation — jamais d'optimisation sur une intuition
12
+ - [ ] Métriques RED par endpoint : Rate, Errors, Duration (P50, P95, P99)
13
+ - [ ] Les requêtes N+1 sont identifiées et résolues (eager loading, batch, JOIN)
14
+ - [ ] Performance budget dans la CI : JS < 200KB, LCP < 2.5s, P95 < 500ms
15
+ - [ ] Les requêtes lentes sont loguées (> 100ms) avec EXPLAIN automatique
16
+ - [ ] Cache en place avec TTL explicite — pas de calcul redondant sur la hot path
17
+
18
+ ## Anti-patterns
19
+ ### Optimisation prématurée
20
+ **Ce qu'on voit :** micro-optimisations de boucles, bit-shifting, allocation pooling — sur un endpoint appelé 100×/jour. Le code est devenu illisible pour gagner 2ms.
21
+ **Pourquoi c'est dangereux :** l'optimisation prématurée a un double coût : le code devient plus dur à maintenir, et le temps passé à optimiser n'est pas passé sur des vrais problèmes. Pire : l'optimisation cible souvent le mauvais endroit parce qu'elle est basée sur l'intuition, pas sur la mesure.
22
+ **Faire plutôt :** "Make it work, make it right, make it fast." Mesurer. Profiler. Identifier le vrai bottleneck (souvent une requête DB, pas une boucle). Optimiser là où le profiling montre un gain. Si le gain est < 10%, se demander si la complexité ajoutée le justifie.
23
+
24
+ ### Optimiser la moyenne
25
+ **Ce qu'on voit :** "la latence moyenne est de 200ms, c'est bon." Le P95 est à 8 secondes — 5% des utilisateurs attendent 8 secondes. Mais la moyenne est belle.
26
+ **Pourquoi c'est dangereux :** la moyenne est insensible aux outliers. 95% des requêtes à 50ms + 5% à 10s = moyenne de ~550ms. Tu regardes 550ms et tu penses "acceptable". Mais 5% de tes utilisateurs ont une expérience exécrable. Les percentiles existent pour cette raison précise.
27
+ **Faire plutôt :** P50 (médiane), P95, P99. Le P95 est l'expérience "normale dans le pire cas". Le P99 est l'expérience "vraiment mauvaise". Alerter et optimiser sur les percentiles, pas sur la moyenne.
28
+
29
+ ### Cache sans stratégie
30
+ **Ce qu'on voit :** `cache.set(key, data)` sans TTL. Le cache garde des données stales indéfiniment. Ou pire : le cache est invalidé à chaque écriture mais jamais rechargé (cache toujours vide).
31
+ **Pourquoi c'est dangereux :** un cache mal conçu est pire que pas de cache — il ajoute de la latence (aller-retour Redis) pour servir des données périmées ou pour ne jamais avoir de hit. Le hit rate est la métrique qui dit si ton cache sert à quelque chose.
32
+ **Faire plutôt :** TTL explicite basé sur la fraîcheur acceptable. Surveiller le hit rate — si < 50%, le cache est probablement mal configuré. Cache-aside pour les lectures, write-through pour les lectures après écriture.
33
+
34
+ ## Patterns
35
+ ### Performance budget
36
+ **Quand :** application web ou mobile.
37
+ **Comment :** définir des seuils dans la CI. JS bundle < 200KB, page weight < 1MB, LCP < 2.5s, TTI < 3s, P95 API < 500ms. Si la PR dépasse, bloquer. Le budget force la discipline — comme un budget financier, tu ne peux pas ajouter sans enlever ailleurs.
38
+
39
+ ### Slow query monitoring
40
+ **Quand :** toute application avec une base de données.
41
+ **Comment :** loguer toute requête > 100ms avec son EXPLAIN ANALYZE. Dashboard des slow queries. Alerte si une nouvelle slow query apparaît (requête qui était rapide avant, lente maintenant = probablement un index ou un volume de données). Chaque slow query est un ticket.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: reactive
3
+ description: "Programmation Reactive — observables, streams, RxJS, backpressure, event sourcing, flux de donnees. A charger quand on utilise un paradigme reactif ou des streams."
4
+ ---
5
+
6
+ # Programmation Reactive
7
+
8
+ **Principe premier :** La programmation reactive n'est pas "utiliser RxJS" — c'est traiter les donnees comme un flux continu plutot que comme des valeurs ponctuelles. Dans un modele imperatif, tu demandes la valeur (`let x = getValue()`). Dans un modele reactif, tu t'abonnes au changement (`stream.subscribe(x => ...)`). La difference fondamentale : le code reactif se declare une fois et reagit a N evenements, le code imperatif repond a chaque evenement individuellement. Le piege : la complexite explose avec le nombre de streams. Sans gestion de la backpressure (producteur plus rapide que le consommateur) et du cycle de vie (unsubscribe), les streams deviennent une source de fuites memoire et de bugs subtils.
9
+
10
+ ## Checklist
11
+ - [ ] Les streams sont unsubscribed proprement (`takeUntil`, `async pipe`, `DisposeBag`) — zero fuite memoire
12
+ - [ ] La backpressure est geree : le consommateur controle le debit (`buffer`, `throttle`, `sample`, `request(n)`)
13
+ - [ ] Les operateurs sont composees en pipeline lisible — pas de callback hell reactive
14
+ - [ ] Les erreurs sont propagees dans le stream — pas de `try/catch` autour de `.subscribe()`
15
+ - [ ] Les streams partages sont multicastes (`share`, `shareReplay`) — pas de side effect par souscripteur
16
+ - [ ] Les valeurs initiales sont definies (`BehaviorSubject`, `startsWith`) — pas de "le stream emet dans 5 secondes"
17
+ - [ ] Le debounce/throttle est utilise pour les evenements frequents (input utilisateur, scroll) — pas de traitement par frappe
18
+
19
+ ## Anti-patterns
20
+ ### Nested subscribes
21
+ **Ce qu'on voit :** `stream1.subscribe(x => { stream2.subscribe(y => { stream3.subscribe(z => { doSomething(x,y,z) }) }) })`. Trois niveaux de souscriptions imbriquees.
22
+ **Pourquoi c'est dangereux :** c'est le callback hell version reactive. Chaque subscribe est un effet de bord. Impossible de unsubcribe proprement. La gestion d'erreur est cassee. Si `stream1` emet pendant que `stream2` n'a pas fini → race condition. Le code est illisible et indetachable.
23
+ **Faire plutot :** `combineLatest([stream1, stream2, stream3]).pipe(takeUntil(destroy$)).subscribe(([x,y,z]) => doSomething(x,y,z))`. Un seul subscribe. Flat/compose, never nest.
24
+
25
+ ### Pas de gestion de backpressure
26
+ **Ce qu'on voit :** un stream de clics souris a 1000 events/s. Le consommateur traite chaque event (appel API). La file d'attente memoire explose.
27
+ **Pourquoi c'est dangereux :** le producteur et le consommateur ont des vitesses differentes. Sans backpressure, le consommateur est inonde. Memoire → ∞. L'app freeze. Le comportement est non deterministe (depend de la charge).
28
+ **Faire plutot :** `sampleTime(200)` (prendre un event toutes les 200ms), `debounceTime(300)` (attendre 300ms de silence), `throttleTime(500)` (max 1 emission toutes les 500ms). Le consommateur controle le debit, pas le producteur.
29
+
30
+ ### RxJS partout
31
+ **Ce qu'on voit :** tout est un observable. `Observable.of(42)`, `Observable.from([1,2,3])`. Même les valeurs synchrones passent par des streams.
32
+ **Pourquoi c'est dangereux :** la programmation reactive ajoute de la complexite cognitive et un surcout de performance. Pour des donnees synchrones (un tableau, une variable), un observable est un marteau-piqueur pour ouvrir une noix. Le code devient plus dur a lire sans benefice.
33
+ **Faire plutot :** utiliser les observables la ou l'asynchronisme et le temps sont intrinseques : evenements utilisateur, websockets, reponses serveur, timers. Pour le synchrone, les structures de donnees normales suffisent.
34
+
35
+ ## Patterns
36
+ ### takeUntil pour le cleanup
37
+ **Quand :** tout abonnement qui a une duree de vie < l'application (composant Angular, ecran React).
38
+ **Comment :** `destroy$ = new Subject<void>()`. Tous les pipelines se terminent par `.pipe(takeUntil(this.destroy$))`. Dans `ngOnDestroy` / `useEffect` cleanup : `this.destroy$.next(); this.destroy$.complete()`. Tous les abonnements sont nettoyes en une ligne.
39
+
40
+ ### Event bus central
41
+ **Quand :** communication entre composants non relies (pas de parent-enfant).
42
+ **Comment :** un `Subject` ou `EventEmitter` partage. Les producteurs emettent, les consommateurs souscrivent. Chaque message est un type specifique (pas de `any`). Le bus est mockable en test. Alternative a Redux pour les cas simples ou la communication est le seul besoin.
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: release-management
3
+ description: "Release Management — releases as contracts, semver as communication, pre-release channels (alpha/beta/rc), signed provenance, changelog as consumer signal. À charger quand on prépare une release."
4
+ ---
5
+
6
+ # Release Management
7
+
8
+ **Principe premier :** Une release est un contrat avec les consommateurs. Le numéro de version n'est pas un compteur — c'est un signal. MAJOR veut dire "tu dois migrer, voici comment". MINOR veut dire "nouveau, sans risque, upgrade". PATCH veut dire "sécurité ou bug, fais-le maintenant". Si tes numéros de version ne communiquent pas ça, ils ne servent à rien. Le changelog est la partie visible de ce contrat — sans lui, les consommateurs ne savent pas ce qui a changé et n'upgraderont pas.
9
+
10
+ ## Checklist
11
+ - [ ] La version suit semver strict : MAJOR (breaking API), MINOR (nouveau compatible), PATCH (bug/security)
12
+ - [ ] Chaque breaking change a un guide de migration (pas juste "changed X" — quoi changer, ligne par ligne)
13
+ - [ ] Des pre-release channels existent : alpha (instable, dev), beta (feature-complete, testable), rc (release candidate, plus de bugs connus)
14
+ - [ ] Le changelog est lisible par un humain — pas un dump de commits, pas de jargon interne
15
+ - [ ] Les artefacts sont signés ET vérifiables (Cosign/Sigstore, checksums SHA256, SBOM)
16
+ - [ ] Le tag Git est signé ET correspond exactement au commit du build (pas de tag après coup)
17
+ - [ ] Les releases sont immutables — jamais de repush d'un tag, jamais de republish d'un package
18
+
19
+ ## Anti-patterns
20
+ ### Version bloquée
21
+ **Ce qu'on voit :** `"version": "1.0.0"` dans package.json depuis 2 ans. 47 commits, des breaking changes, des nouvelles features — la version n'a jamais bougé.
22
+ **Pourquoi c'est dangereux :** la version ne communique plus rien. Les consommateurs ne savent pas s'ils peuvent upgrade. Certains pinent au commit, d'autres prennent `latest` et cassent. Le projet perd la confiance de son écosystème.
23
+ **Faire plutôt :** version bump à chaque release. Automatiser via conventional commits + semantic-release. Chaque merge sur main → version calculée → changelog mis à jour → release. Zéro intervention humaine.
24
+
25
+ ### Changelog = dump de commits
26
+ **Ce qu'on voit :** CHANGELOG.md copié-collé depuis `git log --oneline`. "fix: bug", "wip", "cleanup", "fix test" — l'utilisateur ne comprend rien.
27
+ **Pourquoi c'est dangereux :** un changelog illisible est pire qu'inexistant. Il donne l'illusion d'information. Le consommateur doit lire le diff pour comprendre ce qui a changé — exactement ce que le changelog devait éviter.
28
+ **Faire plutôt :** changelog structuré : Added, Changed, Deprecated, Removed, Fixed, Security. Chaque entrée est une phrase compréhensible par un utilisateur du projet. Le changelog répond à : "Qu'est-ce que je dois faire pour upgrade ?"
29
+
30
+ ### Pre-release sauté
31
+ **Ce qu'on voit :** `1.0.0-alpha.1` existe, puis directement `1.0.0`. Pas de beta, pas de RC. 6 mois entre alpha et stable.
32
+ **Pourquoi c'est dangereux :** les early adopters sont punis. Ils testent l'alpha, trouvent des bugs, mais n'ont jamais de version stable de leurs retours. Ils arrêtent de tester les pre-releases. La release stable sort sans validation réelle.
33
+ **Faire plutôt :** pipeline de maturité : alpha (semaine 1, cassant) → beta (semaine 2-3, testable, feedback) → rc (semaine 4, gel, uniquement bugfixes) → stable. Chaque étape a des consommateurs différents : devs internes → early adopters → tout le monde.
34
+
35
+ ### Artefact mutable
36
+ **Ce qu'on voit :** `npm publish` puis `npm publish` à nouveau sur la même version parce que "j'ai oublié un fichier". Ou `git tag -d v1.2.3 && git tag v1.2.3`.
37
+ **Pourquoi c'est dangereux :** un artefact mutable détruit la reproductibilité. Le hash que tu as vérifié hier n'est plus valide aujourd'hui. Impossible de faire un audit. Les mirrors de registre ont des versions différentes. C'est un cauchemar de debugging.
38
+ **Faire plutôt :** une version = un artefact = un hash, pour toujours. Si bug → nouvelle version (1.2.4, pas 1.2.3 repush). La plupart des registres permettent de "deprecate" sans "unpublish".
39
+
40
+ ## Patterns
41
+ ### Conventional Commits → release automatisée
42
+ **Quand :** tout projet avec plus d'un mainteneur.
43
+ **Comment :** `feat:` → MINOR bump, `fix:` → PATCH bump, `feat!:` ou `BREAKING CHANGE:` → MAJOR bump. `semantic-release` lit l'historique de commits depuis la dernière release, calcule la version, génère le changelog, publie. Configuré une fois, oublié.
44
+
45
+ ### Pre-release channels
46
+ **Quand :** projet avec breaking changes fréquents ou base d'utilisateurs qui teste les versions beta.
47
+ **Comment :** `1.0.0-alpha.1` → tags `alpha` instables. `1.0.0-beta.1` → tag `beta`, feature-complete. `1.0.0-rc.1` → tag `rc`, plus de bugs connus. `1.0.0` → tag `latest`. Les consommateurs choisissent leur niveau de risque : `npm install pkg@beta` ou `npm install pkg@latest`.
48
+
49
+ ### Migration guide
50
+ **Quand :** tout MAJOR bump.
51
+ **Comment :** un fichier `MIGRATION.md` ou section dans le changelog. Format : "Avant → Après" pour chaque breaking change. Exemple de code avant, exemple après. Pourquoi le changement a été fait (pas juste "changed"). Liste des choses à vérifier après migration.
@@ -0,0 +1,69 @@
1
+ ---
2
+ name: research
3
+ description: "Recherche web — stratégies de recherche, évaluation des sources, documentation officielle, issues GitHub, pertinence et fraîcheur de l'information. À charger avant toute recherche d'information externe."
4
+ ---
5
+
6
+ # Recherche Web
7
+
8
+ **Principe premier :** La qualité du code dépend de la qualité de l'information qui l'a inspiré. Une recherche bâclée produit du code basé sur des articles de blog obsolètes, des réponses StackOverflow sans contexte, ou pire — des hallucinations confondues avec des faits. La recherche est une compétence technique : savoir quoi chercher, où chercher, comment évaluer, et quand s'arrêter. Le but n'est pas de tout lire — c'est de trouver l'information la plus fiable et pertinente en un minimum de temps.
9
+
10
+ ## Hiérarchie des sources (par ordre de confiance)
11
+ 1. **Documentation officielle** — docs du framework/langage, spécifications, RFCs
12
+ 2. **Code source** — le code est la documentation ultime, il ne ment jamais
13
+ 3. **Changelogs / release notes** — pour les changements de comportement entre versions
14
+ 4. **Issues GitHub officielles** — bugs connus, discussions de design, workarounds
15
+ 5. **StackOverflow / forums** — uniquement si la réponse a > 10 votes et date de < 2 ans
16
+ 6. **Articles de blog / Medium** — uniquement de la part de mainteneurs officiels ou experts reconnus
17
+ 7. **LLM / connaissances internes** — dernier recours, toujours vérifier avec une source primaire
18
+
19
+ ## Checklist
20
+ - [ ] La recherche part d'une source officielle (pas d'un blog ou d'une réponse StackOverflow)
21
+ - [ ] La version de la doc correspond à la version utilisée dans le projet (pas de doc v2 pour un projet en v1)
22
+ - [ ] Au moins deux sources indépendantes confirment une information critique (pas de single-source confirmation)
23
+ - [ ] Les issues GitHub sont vérifiées : open vs closed, date de dernière activité, lien à un PR de fix
24
+ - [ ] Pour un bug : l'issue a été reproduite par quelqu'un d'autre, pas juste signalée
25
+ - [ ] Pour une solution : le PR qui la contient est mergé et released, pas juste proposé
26
+ - [ ] La fraîcheur est évaluée : < 6 mois (excellent), < 2 ans (bon), > 2 ans (vérifier si toujours valide)
27
+
28
+ ## Anti-patterns
29
+ ### Première page Google = vérité
30
+ **Ce qu'on voit :** recherche Google, premier lien (souvent un blog), copie de la solution sans vérifier qui l'a écrite ni quand.
31
+ **Pourquoi c'est dangereux :** le SEO n'est pas un indicateur de qualité. Les articles de blog optimisés SEO sont souvent écrits par des juniors qui reproduisent ce qu'ils ont vu ailleurs (cargo cult). La solution peut être obsolète, incorrecte, ou dangereuse. Le pire : elle peut marcher dans le cas simple mais échouer silencieusement en production.
32
+ **Faire plutôt :** commencer par la documentation officielle. Le site de doc du framework a un search — l'utiliser. Si Google est nécessaire, ajouter `site:docs.official.com` ou `site:github.com/org/repo/issues`. Filtrer par date (< 1 an). Croiser avec une deuxième source avant d'adopter.
33
+
34
+ ### Solution StackOverflow sans contexte
35
+ **Ce qu'on voit :** copier-coller une réponse StackOverflow acceptée sans lire la question complète, les commentaires, ou les autres réponses.
36
+ **Pourquoi c'est dangereux :** la réponse acceptée n'est pas toujours la meilleure — c'est celle qui a résolu le problème de l'OP. Le contexte peut être différent (version différente, contrainte différente). Les commentaires contiennent souvent des corrections critiques ("this breaks in v3", "deprecated since...").
37
+ **Faire plutôt :** lire la question complète (même contexte ?), les 2-3 réponses les plus votées (pas juste l'acceptée), les commentaires sous chaque réponse (corrections, mises en garde), et vérifier la date. Une réponse de 2015 peut être dangereuse en 2026.
38
+
39
+ ### Hallucination de documentation
40
+ **Ce qu'on voit :** le LLM affirme qu'une API existe avec certaines options. Pas de vérification. Le code est écrit avec une API inexistante.
41
+ **Pourquoi c'est dangereux :** les LLMs mélangent les versions, inventent des paramètres plausibles, et confondent les frameworks similaires (React 17 vs 19, Python 2 vs 3, Express vs Fastify). L'information inventée est souvent syntaxiquement correcte mais sémantiquement fausse — le compilateur ne la détecte pas.
42
+ **Faire plutôt :** toute API utilisée pour la première fois doit être vérifiée dans la doc officielle. Si le LLM dit `fetch(url, { retries: 3 })` — vérifier que `retries` existe vraiment dans l'API fetch. Ne jamais faire confiance à un nom de paramètre ou une signature de fonction sans vérification.
43
+
44
+ ### Ignorer les issues fermées
45
+ **Ce qu'on voit :** on cherche un bug, on trouve une issue ouverte qui décrit le même problème. On s'arrête là. Mais l'issue fermée #1452 contenait la vraie solution, mergée il y a 3 semaines.
46
+ **Pourquoi c'est dangereux :** les issues fermées contiennent les solutions. Les issues ouvertes contiennent les problèmes. Chercher seulement les ouvertes = ignorer tout ce qui a déjà été résolu. Le bug que tu rencontres a peut-être déjà un fix dans la dernière release.
47
+ **Faire plutôt :** toujours chercher les issues fermées ET ouvertes. Une issue fermée avec un PR lié → lire le PR, vérifier dans quelle release il est inclus. Une issue fermée sans PR → lire pourquoi (wontfix ? duplicate ?). Les issues fermées récemment (< 1 mois) sont des mines d'or.
48
+
49
+ ### Single-source confirmation
50
+ **Ce qu'on voit :** une information critique (auth, sécurité, migration) est confirmée par UNE seule source. Pas de vérification croisée.
51
+ **Pourquoi c'est dangereux :** une source peut se tromper. Si la seule source qui dit "cette migration est safe" est un commentaire GitHub de 2019 avec 2 pouces, c'est un pari, pas une vérification.
52
+ **Faire plutôt :** règle des deux sources pour toute information critique. La doc officielle + une issue GitHub. Ou le code source + les tests. Si les sources se contredisent → la doc officielle et le code source priment. Toujours documenter quelle source a confirmé quoi.
53
+
54
+ ## Patterns
55
+ ### Stratégie de recherche par couches
56
+ **Quand :** toute tâche qui demande des connaissances externes.
57
+ **Comment :** Couche 1 : doc officielle (site:docs.X.com). Couche 2 : issues GitHub (site:github.com/org/repo/issues). Couche 3 : StackOverflow si et seulement si les deux premières n'ont pas donné de réponse. Chaque couche plus large = confiance plus faible. Arrêter dès qu'une source fiable confirme.
58
+
59
+ ### Vérification de version
60
+ **Quand :** toute lecture de documentation.
61
+ **Comment :** vérifier la version affichée en haut de la page de doc (souvent un dropdown). Comparer avec la version installée (`package.json`, `go.mod`, `Cargo.toml`). Si la doc est en v3 et le projet en v1 → chercher la doc v1 (URL avec `/v1/` ou switcher dans l'UI). Les breaking changes entre versions sont la cause #1 de "pourtant la doc dit que ça marche".
62
+
63
+ ### Évaluation d'issue GitHub
64
+ **Quand :** on lit une issue GitHub pour décider d'une action.
65
+ **Comment :** Checker : (1) statut (open/closed), (2) date de dernière activité (récent = actif), (3) nombre de participants (plusieurs personnes = problème réel), (4) PRs liés (un PR merged = solution disponible), (5) milestones (incluse dans une release ?). Une issue avec 50 commentaires, fermée, avec un PR merged dans la release v2.3 → solution confirmée. Une issue avec 2 commentaires, ouverte depuis 2 ans → probablement pas prioritaire.
66
+
67
+ ### Croisement de sources
68
+ **Quand :** information critique (sécurité, breaking change, deprecation).
69
+ **Comment :** trouver au moins deux sources indépendantes. Exemples de paires valides : doc officielle + changelog, code source + test, issue GitHub + PR mergé. Une paire invalide : deux articles de blog qui citent la même source. Noter les sources dans un commentaire du code ou du PR pour que le prochain développeur sache pourquoi cette décision a été prise.
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: resilience
3
+ description: "Resilience — circuit breakers, retry with backoff, timeouts, bulkheads, graceful degradation. À charger quand on rend un système tolérant aux pannes."
4
+ ---
5
+
6
+ # Resilience
7
+
8
+ **Principe premier :** La résilience n'est pas "gérer les erreurs" — c'est concevoir le système pour qu'il continue à fonctionner (même en mode dégradé) quand ses dépendances tombent. Chaque dépendance externe va tomber un jour. La question n'est pas "est-ce que Redis est fiable ?" mais "que fait mon application quand Redis est down ?". Le circuit breaker n'est pas un pattern — c'est un réflexe : ne pas continuer à appeler un service qui ne répond pas.
9
+
10
+ ## Checklist
11
+ - [ ] Timeouts explicites sur tout appel externe : connect < 2s, read < 5s, request < 10s
12
+ - [ ] Circuit breaker sur chaque dépendance : échecs > N → circuit OPEN → fast fail
13
+ - [ ] Retry avec backoff exponentiel + jitter — pas de retry immédiat, max 3-5 tentatives
14
+ - [ ] Bulkhead : pools de connexions séparés par client/type de requête
15
+ - [ ] Fallback défini pour chaque point de défaillance : cache, defaults, degraded mode
16
+ - [ ] Chaos engineering : tester la résilience en production, pas en théorie
17
+
18
+ ## Anti-patterns
19
+ ### Retry sans backoff
20
+ **Ce qu'on voit :** `while (!ok) { try { call(); ok = true; } catch {} }` — retry immédiat en boucle.
21
+ **Pourquoi c'est dangereux :** thundering herd. Le service en difficulté reçoit 1000× plus de requêtes à cause des retries. L'incident s'aggrave. Un retry immédiat est une attaque DDoS contre soi-même.
22
+ **Faire plutôt :** backoff exponentiel avec jitter. 1s → 2s → 4s → 8s, max 5 tentatives. Le jitter (aléatoire ±25%) empêche la synchronisation des retries de tous les clients.
23
+
24
+ ### Pas de fallback
25
+ **Ce qu'on voit :** si Redis est down → 500 Internal Server Error. Le cache est devenu un point de défaillance unique.
26
+ **Pourquoi c'est dangereux :** une dépendance non-critique (cache, analytics, recommandations) fait tomber tout le service. Le client voit une erreur pour une fonctionnalité qui aurait pu fonctionner sans cette dépendance.
27
+ **Faire plutôt :** si cache down → servir depuis la DB (plus lent mais fonctionnel). Si analytics down → logger localement et réessayer plus tard. Chaque dépendance a un fallback explicite.
28
+
29
+ ### Timeout = 60 secondes
30
+ **Ce qu'on voit :** `http.get(url, { timeout: 60000 })`. L'utilisateur attend 60s.
31
+ **Pourquoi c'est dangereux :** les threads/workers sont bloqués. Le pool s'épuise. L'app devient non-réactive. Un timeout trop long transforme une défaillance partielle en outage total.
32
+ **Faire plutôt :** timeouts agressifs. Connect < 2s, read < 5s. L'utilisateur préfère un échec rapide qu'une attente infinie. Fast fail > slow timeout.
33
+
34
+ ## Patterns
35
+ ### Circuit Breaker
36
+ **Quand :** toute communication avec une dépendance externe.
37
+ **Comment :** CLOSED (normal) → OPEN après N échecs consécutifs → HALF_OPEN après timeout → CLOSED si succes. En OPEN, les appels sont rejetés immédiatement (pas de tentative inutile).
38
+
39
+ ### Bulkhead
40
+ **Quand :** ressources partagées entre différents appels/clients.
41
+ **Comment :** pool de connexions séparé par client. Si un client sature son pool, les autres ne sont pas affectés. Comme les cloisons étanches d'un navire — une voie d'eau ne coule pas le bateau.