@neikyun/ciel 6.11.2 → 6.13.0

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 (125) hide show
  1. package/assets/.claude/agents/ciel-critic.md +71 -12
  2. package/assets/.claude/agents/ciel-explorer.md +59 -18
  3. package/assets/.claude/agents/ciel-improver.md +6 -3
  4. package/assets/.claude/agents/ciel-researcher.md +85 -25
  5. package/assets/.claude/hooks/block-destructive.sh +2 -2
  6. package/assets/.claude/hooks/check-test-first.sh +2 -2
  7. package/assets/.claude/hooks/memory-bootstrap.sh +0 -0
  8. package/assets/.claude/hooks/memory-engine.py +82 -15
  9. package/assets/.claude/hooks/post-tool-write.sh +32 -0
  10. package/assets/.claude/hooks/pre-agent-gate.sh +11 -6
  11. package/assets/.claude/hooks/pre-compact.sh +18 -0
  12. package/assets/.claude/hooks/pre-tool-write.sh +56 -31
  13. package/assets/.claude/hooks/session-start.sh +22 -1
  14. package/assets/.claude/hooks/session-version-check.sh +1 -1
  15. package/assets/.claude/hooks/stop.sh +104 -0
  16. package/assets/.claude/hooks/subagent-stop.sh +54 -0
  17. package/assets/.claude/hooks/track-file.sh +2 -2
  18. package/assets/.claude/hooks/user-prompt-submit.sh +11 -15
  19. package/assets/.claude/settings.json +18 -4
  20. package/assets/AGENTS.md +1 -1
  21. package/assets/CLAUDE.md +103 -175
  22. package/assets/commands/ciel-audit.md +58 -399
  23. package/assets/commands/ciel-create-skill.md +24 -38
  24. package/assets/commands/ciel-eval.md +25 -37
  25. package/assets/commands/ciel-init.md +36 -126
  26. package/assets/commands/ciel-status.md +22 -19
  27. package/assets/commands/ciel-update.md +20 -39
  28. package/assets/platforms/opencode/.opencode/agents/ciel-researcher.md +71 -895
  29. package/assets/platforms/opencode/.opencode/commands/ciel-audit.md +58 -296
  30. package/assets/platforms/opencode/.opencode/commands/ciel-create-skill.md +24 -46
  31. package/assets/platforms/opencode/.opencode/commands/ciel-eval.md +25 -45
  32. package/assets/platforms/opencode/.opencode/commands/ciel-init.md +36 -131
  33. package/assets/platforms/opencode/.opencode/commands/ciel-status.md +22 -24
  34. package/assets/platforms/opencode/.opencode/commands/ciel-update.md +20 -40
  35. package/assets/platforms/opencode/AGENTS.md +4 -4
  36. package/assets/rules/security.md +30 -0
  37. package/assets/rules/testing.md +23 -0
  38. package/assets/skills/agile/SKILL.md +42 -0
  39. package/assets/skills/alerting/SKILL.md +55 -0
  40. package/assets/skills/api-design/SKILL.md +46 -0
  41. package/assets/skills/appsec/SKILL.md +43 -0
  42. package/assets/skills/architecture/SKILL.md +74 -0
  43. package/assets/skills/backend/SKILL.md +41 -0
  44. package/assets/skills/backup-recovery/SKILL.md +42 -0
  45. package/assets/skills/caching/SKILL.md +44 -0
  46. package/assets/skills/cdn/SKILL.md +42 -0
  47. package/assets/skills/chaos/SKILL.md +41 -0
  48. package/assets/skills/cicd-pipeline/SKILL.md +56 -0
  49. package/assets/skills/cloud/SKILL.md +42 -0
  50. package/assets/skills/code-quality/SKILL.md +42 -0
  51. package/assets/skills/code-review/SKILL.md +41 -0
  52. package/assets/skills/communication/SKILL.md +42 -0
  53. package/assets/skills/containers/SKILL.md +42 -0
  54. package/assets/skills/cqrs/SKILL.md +41 -0
  55. package/assets/skills/crypto/SKILL.md +46 -0
  56. package/assets/skills/data-engineering/SKILL.md +42 -0
  57. package/assets/skills/database-design/SKILL.md +46 -0
  58. package/assets/skills/ddd/SKILL.md +45 -0
  59. package/assets/skills/deployment-strategies/SKILL.md +51 -0
  60. package/assets/skills/desktop/SKILL.md +42 -0
  61. package/assets/skills/devsecops/SKILL.md +43 -0
  62. package/assets/skills/event-driven/SKILL.md +46 -0
  63. package/assets/skills/frontend/SKILL.md +41 -0
  64. package/assets/skills/functional/SKILL.md +42 -0
  65. package/assets/skills/high-availability/SKILL.md +42 -0
  66. package/assets/skills/iac/SKILL.md +46 -0
  67. package/assets/skills/logging/SKILL.md +46 -0
  68. package/assets/skills/meta/ciel-improve/SKILL.md +127 -0
  69. package/assets/skills/meta/learnings-capture/SKILL.md +105 -0
  70. package/assets/skills/meta/patch-spec/patch-spec.md +50 -0
  71. package/assets/skills/meta/skill-creator/SKILL.md +115 -0
  72. package/assets/skills/meta/skill-freshness-auditor/SKILL.md +164 -0
  73. package/assets/skills/meta/skill-variant-evaluator/SKILL.md +100 -0
  74. package/assets/skills/meta/skills-first-design-auditor/SKILL.md +192 -0
  75. package/assets/skills/ml-engineering/SKILL.md +42 -0
  76. package/assets/skills/mobile/SKILL.md +42 -0
  77. package/assets/skills/monitoring/SKILL.md +54 -0
  78. package/assets/skills/networking/SKILL.md +42 -0
  79. package/assets/skills/nosql/SKILL.md +41 -0
  80. package/assets/skills/oop-solid/SKILL.md +42 -0
  81. package/assets/skills/performance/SKILL.md +41 -0
  82. package/assets/skills/reactive/SKILL.md +42 -0
  83. package/assets/skills/release-management/SKILL.md +51 -0
  84. package/assets/skills/research/fact-check-claims/SKILL.md +98 -0
  85. package/assets/skills/research/research-forums/SKILL.md +103 -0
  86. package/assets/skills/research/research-github-issues/SKILL.md +103 -0
  87. package/assets/skills/research/research-web-sources/SKILL.md +108 -0
  88. package/assets/skills/research/synthesize-findings/SKILL.md +112 -0
  89. package/assets/skills/research/validate-source-credibility/SKILL.md +103 -0
  90. package/assets/skills/resilience/SKILL.md +41 -0
  91. package/assets/skills/serverless/SKILL.md +42 -0
  92. package/assets/skills/servers/SKILL.md +41 -0
  93. package/assets/skills/sql/SKILL.md +45 -0
  94. package/assets/skills/supply-chain/SKILL.md +41 -0
  95. package/assets/skills/system-design/SKILL.md +91 -0
  96. package/assets/skills/tech-leadership/SKILL.md +46 -0
  97. package/assets/skills/testing/SKILL.md +41 -0
  98. package/assets/skills/tracing/SKILL.md +36 -0
  99. package/assets/skills/utility/branch-cleaner/SKILL.md +195 -0
  100. package/assets/skills/utility/branch-setup/SKILL.md +144 -0
  101. package/assets/skills/utility/changelog-updater/SKILL.md +125 -0
  102. package/assets/skills/utility/commit-writer/SKILL.md +154 -0
  103. package/assets/skills/utility/issue-closer/SKILL.md +106 -0
  104. package/assets/skills/utility/issue-creator/SKILL.md +200 -0
  105. package/assets/skills/utility/pr-merger/SKILL.md +189 -0
  106. package/assets/skills/utility/pr-opener/SKILL.md +180 -0
  107. package/assets/skills/utility/release-publisher/SKILL.md +224 -0
  108. package/assets/skills/workflow/ciel-dev-process/SKILL.md +94 -0
  109. package/assets/skills/workflow/faire-gatekeeper/SKILL.md +3 -1
  110. package/assets/skills/workflow/prouver-verifier/SKILL.md +11 -2
  111. package/dist/cli/check.d.ts.map +1 -1
  112. package/dist/cli/check.js +11 -2
  113. package/dist/cli/check.js.map +1 -1
  114. package/dist/cli/claude.d.ts.map +1 -1
  115. package/dist/cli/claude.js +0 -2
  116. package/dist/cli/claude.js.map +1 -1
  117. package/dist/cli/init.d.ts.map +1 -1
  118. package/dist/cli/init.js +11 -2
  119. package/dist/cli/init.js.map +1 -1
  120. package/dist/cli/opencode.d.ts.map +1 -1
  121. package/dist/cli/opencode.js +2 -1
  122. package/dist/cli/opencode.js.map +1 -1
  123. package/package.json +1 -1
  124. package/assets/commands/ciel-migrate.md +0 -35
  125. package/assets/commands/ciel-refresh.md +0 -91
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: containers
3
+ description: "Containers — multi-stage builds, distroless, non-root, K8s health checks, resource limits, image immutability. À charger quand on travaille avec Docker ou Kubernetes."
4
+ ---
5
+
6
+ # Containers
7
+
8
+ **Principe premier :** Un container n'est pas une VM légère — c'est un process isolé. L'image Docker est un artefact immutable, pas un serveur maintenu à coup de `docker exec`. Chaque couche ajoutée est une surface d'attaque. Le but : l'image la plus petite possible. Et ne jamais tourner en root — non-root est la baseline, pas un bonus.
9
+
10
+ ## Checklist
11
+ - [ ] Multi-stage build : builder (outils) → runtime (artefacts uniquement, minimal)
12
+ - [ ] Image de base minimale : distroless ou Chainguard — pas de shell, pas de package manager
13
+ - [ ] Container non-root (`USER 1001`) — `runAsNonRoot: true` dans K8s
14
+ - [ ] Secrets injectés au runtime (K8s secrets, Vault) — pas dans l'image, pas en ARG
15
+ - [ ] Ressources limitées (CPU/memory limits AND requests) — pas de "illimité"
16
+ - [ ] Health checks : liveness, readiness, startup — les trois
17
+ - [ ] Images taguées par version ET hash de commit — jamais `:latest`
18
+
19
+ ## Anti-patterns
20
+ ### Container en root
21
+ **Ce qu'on voit :** Dockerfile sans `USER`. Le process tourne en root.
22
+ **Pourquoi c'est dangereux :** container compromis = root inside → escalade possible vers l'hôte. La plupart des applications n'ont jamais besoin de root. C'est un défaut historique, pas une nécessité.
23
+ **Faire plutôt :** `USER 1001:1001`. Distroless (pas de shell). `runAsNonRoot: true`, `readOnlyRootFilesystem: true` dans K8s.
24
+
25
+ ### Image obèse
26
+ **Ce qu'on voit :** `FROM node:22` → image de 1.5 Go avec git, curl, npm, code source complet.
27
+ **Pourquoi c'est dangereux :** pull lent = déploiement lent = rollback lent. Surface d'attaque maximale. Coût de stockage.
28
+ **Faire plutôt :** multi-stage : builder compile → runtime minimal. `COPY --from=builder`. Distroless. Image < 100 Mo.
29
+
30
+ ### `:latest` partout
31
+ **Ce qu'on voit :** `image: myapp:latest`. Impossible de savoir quelle version tourne.
32
+ **Pourquoi c'est dangereux :** non-reproductible. Si `latest` change sur le registry, le prochain pod restart aura une version différente. Rollback impossible.
33
+ **Faire plutôt :** tag sémantique + hash de commit. `myapp:v1.2.3`, `myapp:abc1234`. Immutable.
34
+
35
+ ## Patterns
36
+ ### Multi-stage build
37
+ **Quand :** toute image qui compile du code.
38
+ **Comment :** builder (`FROM golang:1.22 AS builder`) → compile → runtime (`FROM gcr.io/distroless/static`) → `COPY --from=builder /app/binary`. Résultat : un binaire et rien d'autre.
39
+
40
+ ### K8s health checks
41
+ **Quand :** tout pod Kubernetes.
42
+ **Comment :** liveness (process vivant ?), readiness (trafic OK ?), startup (init fini ?). Sans readiness, K8s envoie du trafic avant que l'app soit prête → erreurs en boucle.
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: cqrs
3
+ description: "CQRS & Event Sourcing — séparation lecture/écriture, projections, event store, eventual consistency. À charger quand les patterns de lecture et d'écriture divergent radicalement."
4
+ ---
5
+
6
+ # CQRS & Event Sourcing
7
+
8
+ **Principe premier :** CQRS n'est pas une architecture — c'est la reconnaissance d'un fait : lire et écrire sont deux opérations fondamentalement différentes. Une écriture doit protéger des invariants, une lecture doit être rapide et façonnée pour le client. Les forcer dans le même modèle crée un compromis qui ne satisfait ni l'un ni l'autre. L'event sourcing est orthogonal : c'est la décision de stocker des événements (faits) plutôt que l'état courant. CQRS + Event Sourcing n'est pas un package deal — tu peux faire du CQRS sans event sourcing.
9
+
10
+ ## Checklist
11
+ - [ ] Le besoin de CQRS est avéré — les lectures et écritures ont VRAIMENT des patterns différents
12
+ - [ ] Le modèle d'écriture protège les invariants (aggregates, validation)
13
+ - [ ] Le modèle de lecture est optimisé pour les requêtes du client (dénormalisé, pré-calculé)
14
+ - [ ] L'eventual consistency est assumée et documentée — pas de "surprise" pour les utilisateurs
15
+ - [ ] Si event sourcing : l'event store est append-only, les projections sont reconstruisibles
16
+ - [ ] Les événements sont versionnés (schema evolution) — un événement de 2024 doit être lisible en 2026
17
+
18
+ ## Anti-patterns
19
+ ### CQRS pour un CRUD
20
+ **Ce qu'on voit :** CQRS + Event Sourcing pour un formulaire de contact. CommandBus, EventStore, Projections, ReadModels — pour stocker un nom et un message.
21
+ **Pourquoi c'est dangereux :** le coût de cette architecture est énorme : eventual consistency, debugging complexe, replay à maintenir. Pour un CRUD, ce coût n'est jamais amorti. Tu passes 10× plus de temps sur l'infrastructure que sur la logique métier.
22
+ **Faire plutôt :** CRUD simple. Repository pattern. Ajouter CQRS UNIQUEMENT quand les lectures sont ≥ 10× plus fréquentes que les écritures ET que les patterns divergent. Même là, commencer par du CQRS sans event sourcing.
23
+
24
+ ### Event sourcing sans besoin d'audit
25
+ **Ce qu'on voit :** tout le système en event sourcing "au cas où on aurait besoin de l'historique". 200 événements par aggregate, replay de 30 secondes au démarrage.
26
+ **Pourquoi c'est dangereux :** l'event sourcing a un coût permanent : snapshots, upcasters, replay, debugging d'event streams. Si le métier n'a pas besoin de l'historique complet des changements (audit, conformité, debug), ce coût est du gaspillage pur.
27
+ **Faire plutôt :** stocker l'état courant. Logger les changements importants dans une table d'audit séparée (pas l'event store). Event sourcing UNIQUEMENT quand l'historique est une exigence métier, pas technique.
28
+
29
+ ### Projections non monitorées
30
+ **Ce qu'on voit :** la projection de lecture est stale (lag de 50 000 événements). Personne ne le sait. Les utilisateurs voient des données vieilles de 10 minutes.
31
+ **Pourquoi c'est dangereux :** l'eventual consistency sans monitoring devient de l'inconsistance tout court. Le lag des projections est la métrique #1 d'un système CQRS — si tu ne la mesures pas, tu ne sais pas dans quel état est ton système.
32
+ **Faire plutôt :** métriques sur le lag des projections. Alerte si lag > N événements ou > M secondes. Read-model reconstruit automatiquement si trop de lag (pas de rattrapage infini).
33
+
34
+ ## Patterns
35
+ ### CQRS sans Event Sourcing
36
+ **Quand :** lectures et écritures divergent mais l'historique n'est pas requis.
37
+ **Comment :** command → validation → DB transactionnelle (état courant). Projection → vue dénormalisée mise à jour dans la même transaction ou via un worker. Pas d'event store, pas de replay. La complexité est proportionnelle au besoin.
38
+
39
+ ### Event Store
40
+ **Quand :** l'historique complet est une exigence métier (finance, audit, conformité).
41
+ **Comment :** append-only. Chaque événement = un fait passé (`OrderPlaced`, pas `PlaceOrder`). Projections = vues dérivables à tout moment. Snapshots réguliers pour éviter le replay complet.
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: crypto
3
+ description: "Cryptographie — principes premiers (confidentialité/intégrité/authenticité), AES-GCM, bcrypt/argon2, TLS, PKI, rotation de clés, non-invention. À charger quand on manipule de la cryptographie."
4
+ ---
5
+
6
+ # Cryptographie
7
+
8
+ **Principe premier :** La cryptographie n'est pas une boîte à outils — c'est la science de transformer des problèmes de confiance en problèmes de gestion de clés. Chaque opération crypto répond à une des trois propriétés fondamentales : confidentialité (chiffrement), intégrité (hash, MAC), ou authenticité (signature). Si tu ne sais pas laquelle des trois tu cherches, tu ne devrais pas écrire de code crypto. Règle d'or : ne jamais inventer un algorithme, ne jamais implémenter un algorithme standard soi-même — utiliser une bibliothèque éprouvée (libsodium, Tink, WebCrypto).
9
+
10
+ ## Checklist
11
+ - [ ] Les mots de passe sont hashés avec argon2id (ou bcrypt cost ≥ 12) — pas de SHA, pas de MD5
12
+ - [ ] Le chiffrement utilise un algorithme authentifié (AES-256-GCM ou ChaCha20-Poly1305) — pas d'AES-ECB, pas de CBC sans HMAC
13
+ - [ ] Les IV/nonces sont générés aléatoirement à chaque chiffrement — jamais réutilisés
14
+ - [ ] Les clés sont stockées dans un KMS/HSM — pas dans le code, pas dans les variables d'environnement
15
+ - [ ] TLS ≥ 1.2 partout, 1.3 si possible — certificats auto-renouvelés
16
+ - [ ] La rotation des clés est automatisée (max 90 jours) et testée
17
+ - [ ] Les algorithmes obsolètes sont bloqués (MD5, SHA1, DES, 3DES, RC4, RSA < 2048)
18
+
19
+ ## Anti-patterns
20
+ ### Chiffrement "maison"
21
+ **Ce qu'on voit :** `function encrypt(text) { return Buffer.from(text).toString('base64'); }`. Ou pire : un algorithme inventé "parce que c'est plus simple".
22
+ **Pourquoi c'est dangereux :** la cryptographie est le seul domaine où "ça marche" ne veut rien dire. Un algorithme cassé produit un output valide. La sécurité ne se teste pas — elle se prouve mathématiquement. Même les experts se font casser — ta solution maison n'a aucune chance.
23
+ **Faire plutôt :** libsodium (recommandé pour toute nouvelle application), Tink (Google), ou le module `crypto` natif avec AES-256-GCM. Ces bibliothèques ont été auditées, attaquées, et corrigées par des cryptographes.
24
+
25
+ ### Clé statique éternelle
26
+ **Ce qu'on voit :** la même clé AES utilisée depuis 3 ans pour chiffrer toutes les données. Pas de rotation, pas de plan de compromission.
27
+ **Pourquoi c'est dangereux :** la rotation limite le rayon de l'explosion. Si une clé fuit et qu'elle chiffre 3 ans de données, TOUT est compromis. Avec une rotation à 90 jours, seules 90 journées sont exposées. La rotation n'est pas pour le cas où la clé est volée — c'est pour QUAND elle est volée.
28
+ **Faire plutôt :** rotation automatique (AWS KMS, Vault, Google Cloud KMS). Les anciennes clés déchiffrent uniquement, ne chiffrent plus. La rotation est un exercice de routine, pas une urgence.
29
+
30
+ ### MD5/SHA1 pour les mots de passe
31
+ **Ce qu'on voit :** `hashed_password = md5(password)` ou `sha1(password + salt)`.
32
+ **Pourquoi c'est dangereux :** MD5 et SHA1 sont conçus pour être RAPIDES — c'est exactement l'inverse de ce qu'on veut pour des mots de passe. Un GPU peut tester des milliards de hashs par seconde. Avec un mot de passe faible, le compte est compromis en secondes.
33
+ **Faire plutôt :** argon2id (vainqueur du Password Hashing Competition, recommandé par l'OWASP). Sinon bcrypt (cost ≥ 12) ou scrypt. Ces algorithmes sont lents ET résistants aux GPU/ASIC. 100ms par hash, c'est imperceptible pour l'utilisateur, dévastateur pour l'attaquant.
34
+
35
+ ## Patterns
36
+ ### AES-256-GCM (chiffrement authentifié)
37
+ **Quand :** chiffrement de données au repos ou en transit.
38
+ **Comment :** GCM fournit confidentialité + intégrité + authenticité en un seul mode. IV aléatoire de 12 bytes (jamais réutilisé avec la même clé). Tag d'authentification de 16 bytes vérifié AVANT de déchiffrer. Pas de padding (contrairement à CBC). L'échec de vérification du tag = données corrompues ou attaquées.
39
+
40
+ ### Argon2id (hash de mot de passe)
41
+ **Quand :** stockage de mots de passe utilisateur.
42
+ **Comment :** mémoire 64MB, itérations 3, parallélisme 4. Résistant aux GPU (mémoire), aux side-channel (data-dependent), et aux ASIC. Le sel est généré aléatoirement et stocké avec le hash. Augmenter les paramètres tous les 2 ans avec la puissance du matériel.
43
+
44
+ ### Rotation de clés automatisée
45
+ **Quand :** toute clé qui chiffre des données en production.
46
+ **Comment :** le KMS génère une nouvelle clé tous les 90 jours. L'ancienne clé passe en "decrypt only". Les nouvelles données sont chiffrées avec la nouvelle clé. Le déchiffrement essaie la clé courante, puis la liste des anciennes. La rotation est non-destructive et réversible.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: data-engineering
3
+ description: "Data Engineering — pipelines ETL/ELT, Spark/Airflow/dbt, data warehouses, streaming vs batch, qualite des donnees. A charger quand on construit des pipelines de donnees."
4
+ ---
5
+
6
+ # Data Engineering
7
+
8
+ **Principe premier :** Le data engineering n'est pas "deplacer des donnees de A a B" — c'est garantir que les bonnes donnees arrivent au bon moment avec la bonne qualite. La donnee est un passif jusqu'a ce qu'elle soit utilisable — un pipeline qui livre des donnees corrompues ou tardives est pire que pas de pipeline du tout (les decisions sont prises sur des donnees fausses). Le vrai defi n'est pas le volume (tout le monde peut scaler) — c'est la qualite, la fraicheur, et la gouvernance. Un pipeline doit etre idempotent (re-run = meme resultat), observable (chaque etape logue ce qu'elle a fait), et testable (tu peux verifier la sortie sans la comparer a elle-meme).
9
+
10
+ ## Checklist
11
+ - [ ] Le pipeline est idempotent : re-run = meme resultat, pas de doublons, pas d'effet cumulatif
12
+ - [ ] Les donnees sont validees a l'ingestion (schema, types, contraintes) — pas de "on verifiera plus tard"
13
+ - [ ] Le lineage est documente (d'ou viennent ces donnees ? quelles transformations ?) — pas de mystere
14
+ - [ ] Les PII sont anonymisees/scrubbees avant d'entrer dans le warehouse (pas dans les requetes)
15
+ - [ ] Les incremental loads utilisent des watermarks fiables (pas `MAX(updated_at)` sur une table sans index)
16
+ - [ ] Le monitoring couvre : fraicheur (age des donnees), volume (trop/pas assez), qualite (% de nulls)
17
+ - [ ] Les backfills sont testees et reversibles — un backfill qui casse la production est un incident
18
+
19
+ ## Anti-patterns
20
+ ### Pipeline fragile aux changements de schema
21
+ **Ce qu'on voit :** le pipeline fait `SELECT *` et insere dans une table cible. La source ajoute une colonne → le pipeline casse. La source supprime une colonne → le pipeline casse.
22
+ **Pourquoi c'est dangereux :** les schemas evoluent, c'est normal. Un pipeline qui casse a chaque changement de schema est un pipeline qui passe plus de temps en panne qu'en production. Chaque panne = donnees manquantes = decisions sur des donnees incompletes.
23
+ **Faire plutot :** definir un contrat de schema (schema registry, Avro, Protobuf). Evolution compatible : ajouter des colonnes optionnelles, jamais supprimer sans migration. Le pipeline lit les colonnes explicitement, pas `SELECT *`. Tests d'evolution de schema dans la CI.
24
+
25
+ ### "On nettoiera les donnees plus tard"
26
+ **Ce qu'on voit :** ingestion brute de tout. "On fera la qualite dans le data warehouse." 6 mois plus tard : 500 To de donnees, 40% de valeurs nulles, colonnes inutilisables.
27
+ **Pourquoi c'est dangereux :** la qualite des donnees se degrade avec le temps — chaque transformation ajoute une couche d'interpretation. Plus tu attends pour nettoyer, plus c'est dur et cher. Le data warehouse devient un data swamp.
28
+ **Faire plutot :** validation a l'ingestion (schema, types, contraintes metier). Rejeter les donnees invalides dans une dead letter queue, pas dans le warehouse. Les donnees propres sont plus petites, plus rapides, plus utiles.
29
+
30
+ ### Pipeline = boite noire
31
+ **Ce qu'on voit :** le pipeline tourne dans Airflow/Dagster. Pas de logs structures. "Le DAG a echoue" — aucun diagnostic possible sans regarder le code.
32
+ **Pourquoi c'est dangereux :** sans observabilite, chaque echec est une enquete policiere. Les pipelines sont des programmes distribues — ils echouent pour 50 raisons differentes. Sans logs structures (combien de rows traitees, combien de temps par etape, quelles valeurs aberrantes), le MTTR est de l'ordre de l'heure.
33
+ **Faire plutot :** chaque etape logue : nombre de records traites, duree, nombre d'erreurs/valides, watermark utilise. Dashboards de sante par pipeline. Alertes sur deviation (moins de donnees que d'habitude = probleme upstream).
34
+
35
+ ## Patterns
36
+ ### Medaillon architecture (Bronze/Silver/Gold)
37
+ **Quand :** data lake ou data warehouse avec plusieurs consommateurs.
38
+ **Comment :** Bronze = donnees brutes (ingestion, append-only, schema preserve). Silver = donnees nettoyees, deduplicatees, jointes. Gold = donnees metier agreggees, pretes pour la consommation. Chaque couche a un proprietaire et un SLA de fraicheur.
39
+
40
+ ### Watermark incremental
41
+ **Quand :** pipeline qui traite des donnees par lots incrementaux.
42
+ **Comment :** utiliser une colonne de watermark monotone (`updated_at`, `event_time`, `sequence_id`). Stocker le watermark precedent. Charger `WHERE updated_at > last_watermark`. Gerer les late arrivals avec une fenetre de tolerance (ex: recharger les 2 dernieres heures en plus du delta).
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: database-design
3
+ description: "Database Design — le schema comme contrat, normalisation, indexation, migrations sans downtime, UUID vs bigint. À charger quand on crée ou modifie un schéma de base de données."
4
+ ---
5
+
6
+ # Database Design
7
+
8
+ **Principe premier :** Le schéma de base de données est le contrat le plus coûteux à modifier dans une application. Changer du code = redéployer (minutes). Changer un schéma avec 50M rows = migration potentiellement bloquante (heures ou jours). Le design de schéma est donc un exercice d'anticipation : tout ce qui est facile à changer plus tard peut être décidé plus tard ; tout ce qui est dur à changer doit être décidé maintenant. La normalisation n'est pas un dogme — c'est un défaut qui minimise la redondance. Dénormaliser doit être un choix explicite, pas un accident.
9
+
10
+ ## Checklist
11
+ - [ ] Le schéma est en 3NF sauf raison explicite de dénormaliser (documentée)
12
+ - [ ] Chaque table a une primary key — UUID v7 si distribué, bigint si centralisé
13
+ - [ ] Les foreign keys sont définies ET indexées (intégrité + performance)
14
+ - [ ] Les colonnes sont NOT NULL par défaut — nullable est l'exception, justifiée
15
+ - [ ] Les migrations sont réversibles (up + down) et testées en rollback dans la CI
16
+ - [ ] Les migrations sur grosses tables (> 1M rows) utilisent une stratégie sans lock (expand/contract ou gh-ost)
17
+ - [ ] Pas de logique métier dans la DB — triggers et stored procedures = application
18
+
19
+ ## Anti-patterns
20
+ ### JSON pour tout
21
+ **Ce qu'on voit :** `data JSONB NOT NULL` — nom, email, adresse, commandes, tout dans une colonne JSON. "C'est flexible".
22
+ **Pourquoi c'est dangereux :** pas de typage, pas de contrainte, pas d'index utilisable. "Flexible" veut dire "le contrat n'existe pas". Impossible de faire un rapport sans parser toute la table. La DB devient un dump de documents sans structure.
23
+ **Faire plutôt :** colonnes typées pour tout champ connu et requêté. JSONB réservé aux données vraiment variables (metadata, preferences, config). La structure est le produit — ne pas y renoncer pour de la flexibilité.
24
+
25
+ ### Migration = ALTER TABLE direct
26
+ **Ce qu'on voit :** `ALTER TABLE orders ADD COLUMN status VARCHAR NOT NULL DEFAULT 'pending'` lancé sur une table de 10M rows à 14h en production.
27
+ **Pourquoi c'est dangereux :** PostgreSQL locke la table entière pendant l'ALTER. Pour 10M rows, ça peut prendre 20 minutes. Tout le service est down — commandes, paiements, expéditions. La migration en une étape est la cause #1 des outages de DB.
28
+ **Faire plutôt :** expand/contract en 3 étapes : (1) ADD COLUMN sans NOT NULL (instantané), (2) remplir par batches de 1000 rows avec des pauses, (3) ajouter NOT NULL après que toutes les rows ont une valeur. Chaque étape est une migration séparée, déployable et rollbackable indépendamment.
29
+
30
+ ### Index manquant sur FK
31
+ **Ce qu'on voit :** `order_items.order_id REFERENCES orders(id)` sans index sur `order_id`. Un DELETE sur orders déclenche un seq scan de order_items.
32
+ **Pourquoi c'est dangereux :** chaque DELETE/UPDATE cascadé parcourt toute la table enfant. Sur 10M de order_items, un DELETE d'une commande prend 30 secondes au lieu de 1ms. Deadlocks en cascade.
33
+ **Faire plutôt :** règle mécanique : toute foreign key a un index. C'est vérifiable automatiquement (pghero, linter SQL). Pas d'exception.
34
+
35
+ ## Patterns
36
+ ### Expand/Contract (migration sans downtime)
37
+ **Quand :** toute modification de schéma sur une table > 100K rows en production.
38
+ **Comment :** Phase expand : ajouter (colonnes, tables) sans rien supprimer — l'ancien code continue de fonctionner. Phase migrate : backfill par batches. Phase contract : supprimer l'ancien après validation que tout le nouveau code est déployé. Minimum 2 PRs séparées.
39
+
40
+ ### UUID v7 pour PK distribuée
41
+ **Quand :** besoin d'IDs uniques sans séquence centrale, triables chronologiquement.
42
+ **Comment :** UUID v7 = timestamp (48 bits) + random (74 bits). Chronologiquement triable (contrairement à UUID v4), pas de fragmentation d'index B-tree. Généré côté application, pas de round-trip DB pour l'ID.
43
+
44
+ ### Index partiel
45
+ **Quand :** une requête filtre sur une condition qui ne concerne qu'une petite fraction des rows.
46
+ **Comment :** `CREATE INDEX idx_active ON orders (created_at) WHERE status = 'active'`. L'index est plus petit, plus rapide à scanner, plus rapide à mettre à jour. Ne pas indexer ce qui n'est jamais cherché.
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: ddd
3
+ description: "Domain-Driven Design — Bounded Contexts, Ubiquitous Language, Aggregates, Domain Events, Strategic Design. À charger quand on modélise un domaine métier complexe."
4
+ ---
5
+
6
+ # Domain-Driven Design
7
+
8
+ **Principe premier :** DDD n'est pas un pattern technique — c'est une discipline de modélisation. Le but n'est pas d'utiliser Entities, Value Objects et Aggregates. Le but est de faire en sorte que le code parle le même langage que le métier. Si un expert métier lit ton code et ne reconnaît pas son domaine, tu as échoué, peu importe la qualité technique des patterns. Le Ubiquitous Language est le livrable principal — tout le reste en découle.
9
+
10
+ ## Checklist
11
+ - [ ] Le Ubiquitous Language est le même dans le code ET dans les conversations avec le métier
12
+ - [ ] Les Bounded Contexts sont identifiés et leurs frontières sont explicites
13
+ - [ ] Chaque Aggregate a une racine qui protège ses invariants
14
+ - [ ] Les Value Objects sont immutables et validés à la construction
15
+ - [ ] La logique métier est dans le domaine — pas dans les services, pas dans les controllers
16
+ - [ ] Les Repositories sont des interfaces dans le domaine, implémentées dans l'infrastructure
17
+
18
+ ## Anti-patterns
19
+ ### Anemic Domain Model
20
+ **Ce qu'on voit :** `class Order { id, status, total, getters, setters }` — le domaine est un sac de données. Toute la logique est dans `OrderService.process()`, `OrderService.approve()`, etc.
21
+ **Pourquoi c'est dangereux :** le modèle ne protège rien. N'importe quel code peut faire `order.status = "shipped"` sans vérifier le paiement. Les règles métier sont dupliquées. Le code ment sur ce qui est possible.
22
+ **Faire plutôt :** le domaine est le gardien. `order.approve()` vérifie le statut, le stock, le crédit. `order.ship()` vérifie que la commande est approuvée. Les setters publics n'existent pas sur les propriétés qui ont des règles.
23
+
24
+ ### Bounded Context unique
25
+ **Ce qu'on voit :** une table `users` partagée par l'auth, le billing, le shipping, le marketing. Une entité `Order` unique pour tout le système.
26
+ **Pourquoi c'est dangereux :** "Client" ne veut pas dire la même chose pour le support (historique de tickets) et pour la facturation (adresse, TVA). Forcer un modèle unique crée des compromis qui ne satisfont personne et couplent tous les modules ensemble.
27
+ **Faire plutôt :** chaque contexte a sa propre représentation. `SalesContext.Order` a les items et le prix. `ShippingContext.Shipment` a l'adresse et le tracking. Ils communiquent par événements (`OrderPlaced` → le shipping crée son Shipment).
28
+
29
+ ### Tactical sans strategic
30
+ **Ce qu'on voit :** l'équipe utilise Entities, Value Objects, Aggregates, Repositories — mais n'a jamais défini les Bounded Contexts ni le Ubiquitous Language.
31
+ **Pourquoi c'est dangereux :** les patterns tactiques sans design stratégique, c'est comme des murs sans plan d'architecte. Tu construis proprement, mais peut-être au mauvais endroit. Les Bounded Contexts définissent CE QUI va ensemble — sans ça, les Aggregates sont arbitraires.
32
+ **Faire plutôt :** commencer par le strategic design : Event Storming, Context Mapping, Ubiquitous Language. Les patterns tactiques viennent APRÈS, pour implémenter ce qui a été modélisé.
33
+
34
+ ## Patterns
35
+ ### Bounded Context
36
+ **Quand :** le domaine a des significations différentes pour le même terme. "Client" pour le support ≠ "Client" pour la facturation.
37
+ **Comment :** frontière explicite. Chaque contexte a son propre modèle, son propre langage, sa propre persistence. Communication inter-contexte par Domain Events ou API bien définies. Pas de jointure SQL entre contextes.
38
+
39
+ ### Aggregate Root
40
+ **Quand :** un groupe d'objets doit rester cohérent (invariants). Ex: Order + OrderItems. Le total doit toujours = somme des items.
41
+ **Comment :** une entité racine protège l'accès. Toute modification passe par la racine : `order.addItem()`, jamais `orderItem.setPrice()`. Les objets externes ne référencent jamais l'intérieur d'un aggregate — ils passent par la racine.
42
+
43
+ ### Domain Events
44
+ **Quand :** un changement dans un contexte doit être connu d'un autre.
45
+ **Comment :** l'aggregate émet un événement : `OrderPlaced { orderId, customerId, total }`. Les autres contextes s'abonnent. L'événement est un fait passé (past tense), immuable, et contient tout ce dont le consommateur a besoin (pas de référence à l'aggregate).
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: deployment-strategies
3
+ description: "Deployment Strategies — deploy small/deploy often, blue-green, canary, DB migration coordination, feature flags as decoupling, rollback as first-class. À charger quand on planifie ou améliore un déploiement."
4
+ ---
5
+
6
+ # Deployment Strategies
7
+
8
+ **Principe premier :** La CD n'est pas "déployer vite" — c'est déployer PETIT. On ne fait pas de déploiement continu avec des PRs de 2000 lignes. La confiance vient de la taille du diff : un diff de 50 lignes est trivial à debug, un diff de 5000 lignes est un incident en attente. Blue-green, canary, feature flags — toutes ces stratégies sont des filets de sécurité, pas des enablers. Le vrai enabler, c'est la capacité à découper le travail en incréments déployables indépendamment.
9
+
10
+ ## Checklist
11
+ - [ ] La taille du diff est le premier indicateur de risque — si > 500 lignes, découper
12
+ - [ ] DB migration ET rollback de migration testés AVANT le déploiement du code
13
+ - [ ] Health checks définis (liveness ≠ readiness ≠ startup) — basculer le trafic uniquement sur readiness OK
14
+ - [ ] Rollback = un clic ou un revert automatisé (pas de procédure manuelle de 10 étapes)
15
+ - [ ] Feature flags pour tout changement de comportement — dissociation déploiement / activation
16
+ - [ ] Smoke tests automatiques post-déploiement (endpoints critiques, pas toute la suite E2E)
17
+ - [ ] Observabilité du déploiement : dashboards de comparaison avant/après (erreurs, latence, throughput)
18
+
19
+ ## Anti-patterns
20
+ ### Déploiement = événement stressant
21
+ **Ce qu'on voit :** le déploiement est planifié, annoncé, tout le monde est en war room. On prie. Si ça casse, c'est la panique.
22
+ **Pourquoi c'est dangereux :** si déployer fait peur, c'est que la confiance est absente. La peur pousse à déployer moins souvent → les diffs grossissent → encore plus peur → spirale de la mort. Une équipe qui fait vraiment de la CD déploie 10×/jour sans y penser.
23
+ **Faire plutôt :** rendre le déploiement ennuyeux. Automatiser tout ce qui peut l'être. Si le déploiement est stressant, investir dans la confiance (tests, health checks, rollback automatique) plutôt que dans le processus.
24
+
25
+ ### Déploiement et migration DB couplés
26
+ **Ce qu'on voit :** le déploiement inclut une migration DB `ALTER TABLE... NOT NULL`. Le rollback du code est facile, le rollback de la migration est impossible.
27
+ **Pourquoi c'est dangereux :** le couplage code/schema crée des déploiements irréversibles. Si le code est buggé, tu peux rollback le code mais pas la DB → le vieux code casse sur le nouveau schema. C'est la cause #1 des incidents de déploiement qui durent > 1h.
28
+ **Faire plutôt :** règle d'or — la migration DB doit être compatible avec l'ancien ET le nouveau code (expand/contract). Ajouter une colonne sans contrainte, déployer le code qui l'utilise, puis ajouter la contrainte. Chaque étape est réversible. Les migrations sont testées avec le rollback dans la CI.
29
+
30
+ ### Feature flags sans plan de cleanup
31
+ **Ce qu'on voit :** `if (featureFlags.isEnabled("new-checkout-v2"))` partout. Après 6 mois, v1, v2, v3 coexistent. Le code est incompréhensible.
32
+ **Pourquoi c'est dangereux :** les feature flags sont une dette technique à intérêt composé. Chaque flag ajoute une branche, et les branches se multiplient (2^n combinaisons). Sans cleanup, le système devient intestable.
33
+ **Faire plutôt :** chaque flag a une date d'expiration. Une tâche de cleanup est créée au moment où le flag est introduit. Après 100% de rollout, le flag est supprimé dans les 2 semaines. Si un flag existe depuis > 1 mois, il devient une urgence tech.
34
+
35
+ ### Canary sans critère de succès
36
+ **Ce qu'on voit :** "on envoie 5% du trafic au nouveau code et on voit bien". Pas de métrique, pas de seuil, pas de rollback automatique.
37
+ **Pourquoi c'est dangereux :** sans critère objectif, le canary est du théâtre. Personne ne sait à quel moment dire "le canary a échoué". Résultat : le canary "passe" toujours, jusqu'au déploiement complet où le bug explose à 100%.
38
+ **Faire plutôt :** canary avec critères automatiques. "Si P95 latency > +20% OU error rate > +50% pendant 5 min → rollback automatique. Si OK pendant 15 min → 30% → 50% → 100%." La décision est algorithmique, pas humaine.
39
+
40
+ ## Patterns
41
+ ### Expand/Contract pour les migrations DB
42
+ **Quand :** toute modification de schema en production.
43
+ **Comment :** Phase 1 (expand) : ajouter les nouvelles colonnes/tables, le code lit l'ancien et écrit les deux. Phase 2 (migrate) : backfill les données existantes par batches. Phase 3 (contract) : le code ne lit que le nouveau, supprimer l'ancien. Chaque phase est une PR séparée, déployable et rollbackable indépendamment.
44
+
45
+ ### Blue-Green
46
+ **Quand :** zero downtime requis, rollback immédiat nécessaire.
47
+ **Comment :** 2 environnements identiques. Le live (blue) tourne. On déploie sur green, on smoke-test green, on bascule le trafic. Blue reste chaud 24h. Si incident → rebascule sur blue (10 secondes, pas 10 minutes). Le vrai coût est l'infra doublée — à réserver pour les services critiques.
48
+
49
+ ### Feature flags comme architecture
50
+ **Quand :** toute fonctionnalité qui change le comportement utilisateur.
51
+ **Comment :** le flag ne cache pas juste un `if` — il est injecté, testable, avec un fallback explicite. `if (flags.isEnabled("new-checkout", { default: false }))`. Chaque flag est testé avec les deux valeurs dans la CI. Le flag est un contrat temporaire, pas un état permanent.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: desktop
3
+ description: "Desktop — Electron/Tauri/WPF/Qt, auto-update, code signing, distribution, OS integration. A charger quand on developpe une application desktop."
4
+ ---
5
+
6
+ # Desktop
7
+
8
+ **Principe premier :** Une application desktop n'est pas un site web dans une fenetre — c'est un citoyen de l'OS. L'utilisateur attend des raccourcis clavier, un menu contextuel, des notifications systeme, un comportement au focus/blur, une integration avec le fichier systeme. Si ton app ne respecte pas les conventions de l'OS, l'utilisateur la percoit comme "pas finie" meme si elle fonctionne. Le deuxieme defi est la distribution : contrairement au web ou tu deployes sur un serveur, chaque utilisateur a une copie de ton binaire. Si tu ne peux pas le mettre a jour automatiquement, la version buggee reste en circulation indefiniment.
9
+
10
+ ## Checklist
11
+ - [ ] Auto-update fonctionnel et teste (ancienne version → nouvelle version, rollback si echec)
12
+ - [ ] Code signing en place (Apple notarization + Windows Authenticode) — pas de "telecharger depuis parametres"
13
+ - [ ] L'app respecte les conventions de l'OS : menu natif, raccourcis clavier, drag & drop, notifications
14
+ - [ ] Le bundle est minimal : pas de dependances inutiles, pas de fichiers de dev dans le package final
15
+ - [ ] Les chemins de fichiers utilisent les API OS (appData, documents, temp) — pas de chemins hardcodes Unix/Windows
16
+ - [ ] L'app gere le cycle de vie : focus/blur, sleep/wake, quit/relancer, ouverture de fichier par l'OS
17
+ - [ ] Les permissions sont demandees au moment de l'usage, pas au lancement (caméra, mic, fichiers)
18
+
19
+ ## Anti-patterns
20
+ ### Electron = 500MB pour "Hello World"
21
+ **Ce qu'on voit :** une app Electron qui pese 200MB, utilise 500MB de RAM pour afficher un formulaire. "C'est plus facile a developper."
22
+ **Pourquoi c'est dangereux :** l'utilisateur compare avec les apps natives (Slack = electron, VS Code = electron... mais eux ont des equipes d'optimisation dediees). Une app Electron non optimisee est percue comme "lente" et de trop. Les utilisateurs desinstallent.
23
+ **Faire plutot :** si l'app est simple → Tauri (backend Rust, frontend web, binaire < 5MB). Si Electron : tree-shaking, lazy loading, pas de `nodeIntegration`, pas de `remote` module. Mesurer la RAM et le temps de demarrage a chaque release.
24
+
25
+ ### Pas d'auto-update
26
+ **Ce qu'on voit :** l'utilisateur telecharge l'app sur le site web. Version 1.0. Nouvelle version 1.1 → email aux utilisateurs "telechargez la nouvelle version".
27
+ **Pourquoi c'est dangereux :** 90% des utilisateurs ne mettront jamais a jour manuellement. Les bugs de la v1.0 restent en circulation pendant des annees. Le support recoit des tickets sur des bugs deja corriges. La fragmentation des versions est un cauchemar.
28
+ **Faire plutot :** auto-update integre des le jour 1 (electron-updater, Sparkle pour Mac, Squirrel pour Windows). L'app verifie au demarrage et telecharge en arriere-plan. Mise a jour silencieuse pour les patchs, notification pour les features.
29
+
30
+ ### Ignorer les conventions OS
31
+ **Ce qu'on voit :** CTRL+C ne copie pas. CMD+Q ne quitte pas. Le menu est custom et ne ressemble a rien. Les dialogues de fichier sont du HTML custom.
32
+ **Pourquoi c'est dangereux :** les utilisateurs ont des annees de memoire musculaire. Chaque violation de convention = friction cognitive. L'utilisateur ne se dit pas "cette app a un design original" — il se dit "cette app est buggee" et retourne a l'alternative native.
33
+ **Faire plutot :** utiliser les composants natifs quand ils existent (menu, file dialog, notifications). Les raccourcis clavier standard doivent fonctionner. Tester sur Mac et Windows — les conventions sont differentes.
34
+
35
+ ## Patterns
36
+ ### Distribution multi-plateforme
37
+ **Quand :** app qui cible Windows + Mac + Linux.
38
+ **Comment :** CI qui build les 3 plateformes en parallele. Code signing specifique par plateforme (Mac : notarization via `gon`/`electron-notarize`, Windows : Authenticode via Azure Key Vault). Auto-update specifique par plateforme (Sparkle pour Mac, Squirrel.Windows pour Windows, AppImage pour Linux).
39
+
40
+ ### Minimiser la surface d'attaque Electron
41
+ **Quand :** toute app Electron.
42
+ **Comment :** `contextIsolation: true`, `nodeIntegration: false`, `sandbox: true`. IPC pour la communication main-renderer (pas de `remote`). Preload script minimal : exposer uniquement les API necessaires via `contextBridge`. La renderer process est non fiable — traiter chaque message comme du user input.
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: devsecops
3
+ description: "DevSecOps — shift-left security, supply chain integrity, SLSA, attestation, SBOM, CVE triage. À charger quand on intègre la sécurité dans le SDLC."
4
+ ---
5
+
6
+ # DevSecOps
7
+
8
+ **Principe premier :** La sécurité n'est pas une étape dans le pipeline — c'est une propriété émergente du système de développement. Le vrai objectif n'est pas "trouver des vulnérabilités" mais "réduire le temps entre l'introduction d'une vulnérabilité et sa détection". Plus ce délai est court, moins la vulnérabilité a de valeur pour un attaquant. Shift-left n'est pas un slogan : chaque heure gagnée réduit la fenêtre d'exposition.
9
+
10
+ ## Checklist
11
+ - [ ] SAST bloque sur les vulnérabilités critiques — le pipeline ne passe pas, point
12
+ - [ ] Les dépendances sont scannées automatiquement (Snyk/Renovate) avec politique de blocage claire (critique = block, haute = warn + SLA 72h, medium/low = log)
13
+ - [ ] Secret scanning au commit (pre-commit hook) ET dans l'historique (push hook, scheduled scan)
14
+ - [ ] Les images container sont signées (Sigstore/Cosign) et scannées (Trivy/Grype) — signature ET scan, pas l'un sans l'autre
15
+ - [ ] SLSA niveau 2 minimum : provenance attestée, build reproductible, artefacts signés
16
+ - [ ] SBOM généré à chaque build (SPDX ou CycloneDX) — consommable par les clients
17
+ - [ ] Les IaC et policies sont scannés (Checkov, OPA/Kyverno) — pas juste le code applicatif
18
+ - [ ] Les SLA de correction sont mesurés et visibles (critique < 24h, haute < 72h, medium < 30j)
19
+
20
+ ## Anti-patterns
21
+ ### Sécurité à la fin
22
+ **Ce qu'on voit :** SAST lancé une semaine avant la release. 50 CVEs critiques. Release bloquée.
23
+ **Pourquoi c'est dangereux :** plus une vulnérabilité est trouvée tard, plus elle coûte cher à corriger — c'est exponentiel. Une CVE trouvée au commit coûte 10 min, trouvée en staging coûte 2h, trouvée en prod coûte 2 jours + incident. Le coût n'est pas le scan — c'est le délai.
24
+ **Faire plutôt :** sécurité à chaque commit. SAST dans la CI de la PR. Dependency scan automatique hebdomadaire. Le but : détecter dans les minutes, pas dans les semaines.
25
+
26
+ ### Scanner sans bloquer
27
+ **Ce qu'on voit :** Trivy/Dependabot trouvent des CVE, le pipeline reste vert. Les alertes s'accumulent dans une inbox que personne ne lit.
28
+ **Pourquoi c'est dangereux :** un scan qui ne bloque pas n'existe pas. Il produit du bruit, et le bruit tue la vigilance. En 6 mois, l'équipe a appris que "rouge" ne veut rien dire — c'est le pire état possible pour un système de sécurité.
29
+ **Faire plutôt :** politique de blocage stricte et explicite. Critique = pipeline rouge, merge impossible. Haute = avertissement visible + ticket automatique + SLA. Le seuil monte avec le temps (on commence à medium, puis on resserre).
30
+
31
+ ### SBOM comme case à cocher
32
+ **Ce qu'on voit :** un SBOM est généré "parce qu'il faut" mais personne ne le lit, ne le vérifie, ni ne l'utilise en cas d'incident.
33
+ **Pourquoi c'est dangereux :** un SBOM non testé est pire que pas de SBOM — il donne une fausse confiance. Le jour où Log4Shell 2.0 sort, tu ne sais pas quels services sont affectés en < 1h. Le SBOM doit être utilisable en incident.
34
+ **Faire plutôt :** SBOM versionné avec le build, stocké dans un registre requêtable. Test d'audit trimestriel : "Simule une CVE sur le package X. En combien de temps identifies-tu tous les services affectés ?" Si > 10 min, le SBOM n'est pas opérationnel.
35
+
36
+ ## Patterns
37
+ ### Shift-left par étapes
38
+ **Quand :** organiser la sécurité sans tout casser.
39
+ **Comment :** 3 niveaux de maturité. Niveau 1 : secret scan au push, lint de sécurité en CI. Niveau 2 : SAST + dependency scan bloquants, OIDC. Niveau 3 : SLSA build attestation, SBOM signé, policy-as-code en déploiement. On monte d'un niveau par trimestre — pas tout d'un coup.
40
+
41
+ ### Security Champions
42
+ **Quand :** équipe sans security engineer dédié.
43
+ **Comment :** 1 dev par équipe formé à la sécurité (OWASP, threat modeling, revue de dépendances). Ce n'est pas un rôle full-time — c'est un point de contact. Le champion fait la review de sécurité des PRs de son équipe, escalade à l'équipe sécurité centrale pour les cas complexes. La connaissance se diffuse — en 1 an, toute l'équipe monte en compétence.
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: event-driven
3
+ description: "Event-Driven Architecture — pub/sub, idempotence, dead letter queues, ordering, outbox pattern. À charger quand on a des services qui doivent communiquer sans couplage direct."
4
+ ---
5
+
6
+ # Event-Driven Architecture
7
+
8
+ **Principe premier :** L'event-driven architecture n'est pas un pattern d'intégration — c'est une stratégie de découplage temporel. Le producer n'attend pas le consumer. Le consumer n'a pas besoin que le producer soit vivant. Cette indépendance temporelle est la vraie valeur, pas le "pub/sub". Mais elle a un prix : tu perds la consistence immédiate. Tu ne sais pas QUAND le consumer traitera l'événement. Assumer ce trade-off explicitement, c'est ça faire de l'event-driven.
9
+
10
+ ## Checklist
11
+ - [ ] Chaque événement est un fait passé (past tense : `PaymentReceived`, pas `ReceivePayment`)
12
+ - [ ] Chaque consumer est idempotent — même événement reçu 2× = même résultat (pas de double charge)
13
+ - [ ] Dead Letter Queue configurée avec alerte — un message qui échoue > N fois ne bloque pas les autres
14
+ - [ ] L'ordre est géré explicitement quand il est nécessaire (partition key, ordering key)
15
+ - [ ] Les timeouts sont explicites — pas de consumer bloqué à l'infini sur un appel externe
16
+ - [ ] Outbox pattern pour les opérations DB + événement atomiques
17
+ - [ ] Métriques sur chaque file : lag, retry rate, DLQ size, processing time
18
+
19
+ ## Anti-patterns
20
+ ### Chaîne HTTP synchrone déguisée en événementielle
21
+ **Ce qu'on voit :** Service A publie un événement, attend la réponse de B via un autre événement. B attend C, qui attend D. Timeout à 30s.
22
+ **Pourquoi c'est dangereux :** c'est du HTTP synchrone avec plus d'étapes et de points de défaillance. Si D est lent, toute la chaîne timeout. Tu as ajouté la complexité de l'event-driven sans le bénéfice (découplage temporel).
23
+ **Faire plutôt :** si tu as besoin d'une réponse synchrone, fais du HTTP. L'event-driven est pour le "fire and forget" — le producer émet et continue sa vie, le consommateur traite quand il peut.
24
+
25
+ ### Consumer non-idempotent
26
+ **Ce qu'on voit :** le consumer insère en DB sans vérifier si l'événement a déjà été traité. Un retry → double insertion.
27
+ **Pourquoi c'est dangereux :** en event-driven, at-least-once est la règle, pas l'exception. Les retries arrivent. Si ton consumer n'est pas idempotent, chaque retry corrompt les données. Un client débité 2×, un email envoyé 3×.
28
+ **Faire plutôt :** stocker l'event_id traité (dans la même transaction que le traitement). `INSERT ON CONFLICT (event_id) DO NOTHING`. Si l'event_id existe déjà, ACK sans traiter.
29
+
30
+ ### Pas de DLQ
31
+ **Ce qu'on voit :** un message mal formé bloque le consumer. Retry infini. Tous les messages suivants sont bloqués derrière le message poison.
32
+ **Pourquoi c'est dangereux :** un seul message invalide paralyse tout le pipeline d'événements. Le lag s'accumule. Quand le consumer est débloqué, il a 100 000 messages de retard — et certains sont périmés.
33
+ **Faire plutôt :** DLQ après N retries (3-5). Alerte immédiate sur DLQ non vide. Mécanisme de replay depuis la DLQ après correction. Ne jamais ignorer silencieusement la DLQ.
34
+
35
+ ## Patterns
36
+ ### Outbox Pattern
37
+ **Quand :** une opération doit écrire en DB ET publier un événement de manière atomique.
38
+ **Comment :** écrire l'événement dans une table `outbox` dans la MÊME transaction DB que l'écriture métier. Un worker lit l'outbox et publie. Si le publish échoue, il retry. Si le worker crashe, l'événement est dans l'outbox. Garantit at-least-once sans 2PC.
39
+
40
+ ### Idempotency Key
41
+ **Quand :** une opération doit être exécutée exactement une fois.
42
+ **Comment :** le producer génère une clé unique (`idempotency-key`). Le consumer stocke la clé + le résultat. Si la clé est déjà connue → retourner le résultat stocké, ne pas ré-exécuter. Stripe utilise ce pattern pour les paiements.
43
+
44
+ ### Schema evolution
45
+ **Quand :** le format des événements change avec le temps.
46
+ **Comment :** chaque événement a un champ `version` et un `type`. Les upcasters transforment les anciens événements vers le nouveau format au replay. Ne jamais modifier un type d'événement existant — en créer un nouveau (ex: `OrderPlacedV2`).
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: frontend
3
+ description: "Frontend — state management as complexity spectrum, rendering strategy (SSR/CSR/SSG), bundle as UX metric, optimistic UI. À charger quand on touche à du code frontend."
4
+ ---
5
+
6
+ # Frontend
7
+
8
+ **Principe premier :** Le frontend n'est pas "afficher des données HTML" — c'est gérer la complexité d'état sur un appareil qu'on ne contrôle pas. La seule métrique qui compte vraiment est le temps jusqu'à l'interaction (TTI). Tout le reste — state management, code splitting, SSR — est un moyen de réduire le TTI. Si ta stack "moderne" produit un TTI de 5 secondes, elle est moins performante qu'un site HTML vanilla de 2005. L'utilisateur ne voit pas ta stack, il voit le temps de chargement.
9
+
10
+ ## Checklist
11
+ - [ ] Le state management est proportionnel à la complexité : useState → Context → Zustand → Redux (pas l'inverse)
12
+ - [ ] La stratégie de rendu est délibérée : SSR pour SEO, CSR pour apps interactives, SSG pour contenu statique
13
+ - [ ] Le bundle est surveillé : JS < 200KB, lazy loading au-dessus du fold, code splitting par route
14
+ - [ ] Lighthouse ≥ 90 sur perf + a11y + best practices — mesuré dans la CI
15
+ - [ ] Les formulaires gèrent TOUS les états : idle, loading, success, error, validation
16
+ - [ ] L'accessibilité de base est non-négociable : labels, keyboard nav, contrast minimum, ARIA sur les composants interactifs
17
+
18
+ ## Anti-patterns
19
+ ### State management comme religion
20
+ **Ce qu'on voit :** Redux installé pour un formulaire de contact. Store, reducers, actions, selectors, middleware — 50 fichiers pour stocker `{email, message}`.
21
+ **Pourquoi c'est dangereux :** le state management a un coût cognitif. Chaque couche ajoute de l'indirection. Pour un state local à un formulaire, useState suffit. Le bon outil est celui qui résout le problème avec le moins de code — pas celui qui est "le standard de l'industrie".
22
+ **Faire plutôt :** spectre de complexité. useState pour le state local. Context pour le state partagé par < 5 composants. Zustand pour le state global simple. Redux uniquement si tu as besoin de devtools, middleware, et normalisation de state complexes.
23
+
24
+ ### useEffect comme solution à tout
25
+ **Ce qu'on voit :** des chaînes de `useEffect` qui se déclenchent les unes les autres. `useEffect(() => setB(a), [a]); useEffect(() => setC(b), [b])`. Props → state → render → effect → state → render → effect...
26
+ **Pourquoi c'est dangereux :** c'est du state management par effets de bord. Chaque render supplémentaire est une opportunité de bug. Les cascades d'effets créent des états intermédiaires incohérents visibles par l'utilisateur.
27
+ **Faire plutôt :** dériver pendant le rendu. `const derived = computeExpensive(data)` sans useEffect — React le recalcule au bon moment. `useMemo` pour les calculs coûteux, pas pour contourner un problème d'architecture.
28
+
29
+ ### Bundle obèse
30
+ **Ce qu'on voit :** `import { debounce } from "lodash"` → toute la librairie lodash (70KB) dans le bundle pour une fonction de 10 lignes.
31
+ **Pourquoi c'est dangereux :** le bundle est le premier facteur du TTI. 2 Mo de JS sur une connexion 3G = 20 secondes avant que l'utilisateur puisse interagir. La moitié des utilisateurs abandonnent après 3 secondes.
32
+ **Faire plutôt :** `import debounce from "lodash/debounce"`. Bundle analyzer dans la CI (`vite-bundle-visualizer`, `next-bundle-analyzer`). Budget de bundle : si la PR dépasse +50KB, bloquer et justifier.
33
+
34
+ ## Patterns
35
+ ### Suspense boundaries
36
+ **Quand :** chargement asynchrone de données ou de code.
37
+ **Comment :** `<Suspense fallback={<Skeleton />}>` autour du composant asynchrone. Le composant ne gère pas son propre état de chargement — le parent le fait. Permet de composer le chargement (tout chargé → afficher, plutôt que chaque widget avec son spinner).
38
+
39
+ ### Optimistic update
40
+ **Quand :** l'interface doit être perçue comme instantanée.
41
+ **Comment :** mettre à jour l'UI immédiatement comme si l'opération avait réussi. Envoyer la requête au serveur. Si succès → rien à faire. Si échec → rollback + notification d'erreur. L'utilisateur ne voit la latence que si l'opération échoue.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: functional
3
+ description: "Programmation Fonctionnelle — immutabilite, fonctions pures, composition, Result/Option, pattern matching. A charger quand on utilise un style fonctionnel."
4
+ ---
5
+
6
+ # Programmation Fonctionnelle
7
+
8
+ **Principe premier :** La programmation fonctionnelle n'est pas "utiliser `map` et `filter`" — c'est un contrat avec toi-meme : tu ne modifieras pas l'etat existant. Ce contrat elimine une classe entiere de bugs (les mutations surprises, les races conditions sur l'etat mutable, les effets de bord caches). Une fonction pure est un sous-programme qui ne depend QUE de ses parametres et ne produit QUE sa valeur de retour. Pas de `this`, pas de variable globale, pas d'appel DB cache. Le prix a payer : tout copier est plus lent, et certains algorithmes sont plus naturels en imperatif. Le benefice : une fonction pure est testable, parallelisable, et raisonnable isolement — pas besoin de lire 10 fichiers pour comprendre ce qu'elle fait.
9
+
10
+ ## Checklist
11
+ - [ ] Les fonctions sont pures : meme entree → meme sortie, pas d'effet de bord (DB, HTTP, file)
12
+ - [ ] Les donnees sont immutables — pas de `push`, `splice`, `delete`, `sort()` in-place
13
+ - [ ] Les erreurs sont modelisees comme des valeurs (Result<T, E>, Option<T>) — pas d'exceptions non gerees
14
+ - [ ] La composition remplace l'heritage : `compose(f, g)(x)` plutot que `class B extends A`
15
+ - [ ] Les effets de bord sont pousses aux bords du systeme (entree/sortie) — le cœur est pur
16
+ - [ ] Le pattern matching est utilise pour les unions discriminantes — pas de `if (type === "...")` en chaine
17
+ - [ ] Pas de `null` — utiliser `Option<T>` (Some/None) pour les valeurs optionnelles
18
+
19
+ ## Anti-patterns
20
+ ### FP = utiliser des callbacks
21
+ **Ce qu'on voit :** `array.map(x => x * 2).filter(x => x > 5)` et l'equipe pense "on fait de la FP". Mais tout le reste est mutable et impur.
22
+ **Pourquoi c'est dangereux :** la FP n'est pas une liste d'operations sur tableau — c'est une discipline sur l'etat et les effets de bord. Utiliser `map` sans immutabilite, c'est mettre un autocollant "functional" sur du code imperatif. Les vrais bugs sont toujours dans les mutations partagees.
23
+ **Faire plutot :** commencer par l'immutabilite (c'est le plus gros gain). Ensuite pousser les effets de bord aux bords. Enfin, modeliser les erreurs comme valeurs. Les `map`/`filter`/`reduce` viendront naturellement.
24
+
25
+ ### Exception pour le flux de controle
26
+ **Ce qu'on voit :** `throw new UserNotFoundError()` dans un service, `catch (e) { if (e instanceof UserNotFoundError)... }` 3 couches plus haut.
27
+ **Pourquoi c'est dangereux :** l'exception casse le contrat de la fonction. La signature dit `User → UserProfile` mais en realite la fonction peut throw. Le compilateur ne verifie pas les exceptions (dans la plupart des langages). Le flux de controle devient implicite et non type.
28
+ **Faire plutot :** retourner `Result<UserProfile, UserNotFoundError>`. L'appelant est force de gerer les deux cas. Le flux de controle est explicite et type. Pattern matching : `match result { Ok(profile) => ..., Err(UserNotFound) => ... }`.
29
+
30
+ ### Immutabilite = tout copier naivement
31
+ **Ce qu'on voit :** `return { ...state, items: [...state.items, newItem] }` dans un reducer Redux avec 10000 items. Chaque update copie tout le tableau.
32
+ **Pourquoi c'est dangereux :** l'immutabilite naive est O(n) en memoire et en temps. Pour une liste de 100000 elements, 100 updates/s = 10 millions de copies = memoire explose. L'equipe conclut "la FP c'est lent" alors que c'est juste l'implementation.
33
+ **Faire plutot :** structures de donnees persistantes (Immutable.js, Immer avec structural sharing). Elles partagent la memoire entre les versions. O(log n) ou O(1) pour la plupart des operations. L'immutabilite n'est pas lente — la copie naive l'est.
34
+
35
+ ## Patterns
36
+ ### Result/Either type
37
+ **Quand :** toute operation qui peut echouer pour une raison connue (validation, lookup, parsing).
38
+ **Comment :** `type Result<T, E> = Ok<T> | Err<E>`. L'appelant pattern-match sur le resultat. Tous les chemins sont types et verifies. Pas de `try/catch` pour le flux normal. Les erreurs font partie du contrat de la fonction.
39
+
40
+ ### Sandwitch fonctionnel (IO sandwich)
41
+ **Quand :** une operation qui doit lire des donnees, les transformer, et ecrire le resultat.
42
+ **Comment :** (1) Lire toutes les donnees necessaires (IO, impur), (2) transformation pure en memoire (cœur, pur), (3) ecrire le resultat (IO, impur). Les entrees/sorties sont aux bords, le cœur est pur et testable sans mocks.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: high-availability
3
+ description: "Haute Disponibilite — clustering, failover, multi-region, quorum, split-brain, replication, SLA 9s. A charger quand on concoit un systeme haute disponibilite."
4
+ ---
5
+
6
+ # Haute Disponibilite
7
+
8
+ **Principe premier :** La haute disponibilite n'est pas "avoir des serveurs de backup" — c'est concevoir pour la defaillance comme cas nominal. Tout composant va tomber un jour. La question n'est pas "est-ce que ca va tomber ?" mais "quand ca tombe, est-ce que le systeme continue ?". Le SLA (99.9%, 99.99%, 99.999%) n'est pas un objectif de disponibilite — c'est un budget de panne. 99.9% = 8h46min d'indisponibilite par an. 99.99% = 52min. 99.999% = 5min. Chaque 9 supplementaire coute un ordre de grandeur en complexite et en argent. Le vrai defi de la HA n'est pas technique — c'est economique : jusqu'ou vas-tu pour 9 de plus ?
9
+
10
+ ## Checklist
11
+ - [ ] Le SLA cible est defini (99.9%, 99.99%, 99.999%) et connu de l'equipe + budget de panne annuel calcule
12
+ - [ ] Le failover est automatise (pas de bascule manuelle a 3h du mat) — detection + basculement < SLA
13
+ - [ ] Chaque composant est deploye sur au moins 2 zones de disponibilite (ou 2 regions) — pas de SPOF
14
+ - [ ] Le quorum est configure correctement (3 ou 5 nœuds, jamais 2) pour eviter le split-brain
15
+ - [ ] La replication est monitorisee (lag en secondes) — alerter si lag > seuil
16
+ - [ ] Les tests de failover sont executes regulierement (trimestriel) — sans test, la HA est une croyance
17
+ - [ ] Le load balancer fait du health checking actif (endpoint applicatif, pas juste TCP connect)
18
+
19
+ ## Anti-patterns
20
+ ### Cluster a 2 nœuds
21
+ **Ce qu'on voit :** 2 serveurs en cluster. Le reseau entre eux coupe. Chacun pense que l'autre est mort et devient primaire → deux primaires → corruption de donnees.
22
+ **Pourquoi c'est dangereux :** avec 2 nœuds, aucun quorum n'est possible (majorite = 2/2). En cas de partition reseau, chaque nœud a 50% de chances — pas de majorite. Le split-brain est inevitable. C'est la configuration la plus dangereuse.
23
+ **Faire plutot :** minimum 3 nœuds pour un cluster. La majorite est 2/3 → un seul cote de la partition peut avoir le quorum. Pour les systemes a 2 nœuds, utiliser un témoin externe (witness, quorum disk) qui donne la majorite a UN des deux.
24
+
25
+ ### HA = juste dupliquer les serveurs
26
+ **Ce qu'on voit :** 2 serveurs d'application derriere un load balancer. "On est HA." La base de donnees est un seul RDS sans Multi-AZ.
27
+ **Pourquoi c'est dangereux :** la HA est aussi forte que ton maillon le plus faible. Serveurs app HA + DB single point of failure = la DB tombe, tout tombe. Les utilisateurs voient "error 500", pas "la DB est down". La HA est une propriete du systeme entier, pas d'un composant.
28
+ **Faire plutot :** analyser le chemin critique complet. Load balancer (redondant), serveurs app (≥2, multi-AZ), DB (multi-AZ ou cluster), cache (cluster Redis), file d'attente (cluster). Chaque composant doit survivre a la perte d'un nœud. Le test de resilience verifie le systeme entier.
29
+
30
+ ### Pas de test de failover
31
+ **Ce qu'on voit :** Multi-AZ configure. Le failover est "automatique". Personne ne l'a jamais declenche volontairement.
32
+ **Pourquoi c'est dangereux :** le failover automatique est un systeme complexe : detection de panne, election d'un nouveau primaire, reconfiguration DNS/proxy, reconnection des clients. Chaque etape peut echouer. La premiere fois que le failover est teste ne doit pas etre le jour de la panne reelle.
33
+ **Faire plutot :** Game Day trimestriel : on coupe le primaire et on observe le failover. Mesurer le temps de bascule. Verifier que les clients se reconnectent. Verifier que les donnees sont intactes. Documenter ce qui a mal tourne. Le failover non teste = pas de failover.
34
+
35
+ ## Patterns
36
+ ### Active-Passive avec health check
37
+ **Quand :** service avec etat (DB, file system).
38
+ **Comment :** un seul nœud actif (ecritures). Un ou plusieurs nœuds passifs (lecture seule ou standby). Health check continu sur l'actif. Si l'actif ne repond plus → promotion du standby le plus a jour via leader election (quorum). Les clients sont redirigés vers le nouveau primaire.
39
+
40
+ ### Multi-AZ stateless
41
+ **Quand :** services sans etat (API, workers).
42
+ **Comment :** deployer N instances reparties sur ≥2 zones de disponibilite. Load balancer repartit le trafic. Si une AZ tombe, le load balancer envoie tout le trafic vers les autres AZ. Aucune intervention humaine. Le nombre d'instances doit absorber la perte d'une AZ entiere sans saturation.