[Factory](../../../README.md) > [Doc](../../README.md) > [Runbooks](../README.md) > **Nouvelle application web**
# Mettre en service une nouvelle application web
> **Last Updated:** 2026-05-31
> **Status:** ✅ Procédure courante
> **Related:** [Conventions de nommage](conventions.md) · [Checklist](08-checklist.md) · [ADR CI/CD](../../adr/03_cicd_gitea_action_argocd.md) · [ADR Vault](../../adr/04_tool_hashicorp_vault.md)
## C'est quoi ?
Ce runbook décrit, de zéro, comment faire vivre une nouvelle application web sur la plateforme Arcodange. Le pattern est **GitOps** : l'app habite son propre dépôt Gitea, sa base de données et ses accès Vault sont provisionnés par Terraform/OpenTofu, et **ArgoCD** déploie son chart Helm dans un namespace dédié. Les identifiants Postgres ne sont jamais écrits en clair : ils sont générés à la volée par Vault et injectés dans le pod par le **Vault Secrets Operator (VSO)**.
La mécanique est répartie sur **trois dépôts** — le dépôt plateforme [`factory`](https://gitea.arcodange.lab/arcodange-org/factory), le dépôt des services partagés [`tools`](https://gitea.arcodange.lab/arcodange-org/tools), et le **nouveau dépôt de l'app** — avec des **dépendances d'ordre** strictes (voir plus bas). Les exemples de référence sont [`erp`](https://gitea.arcodange.lab/arcodange-org/erp) (image publique + DB) et [`webapp`](https://gitea.arcodange.lab/arcodange-org/webapp) (image maison + DB).
**Sert à :**
1. Créer un dépôt Gitea et son squelette (`chart/`, `iac/`, `.gitea/workflows/`).
2. Provisionner la base de données, son rôle propriétaire, et les accès Vault (statiques + dynamiques).
3. Déployer l'app via ArgoCD et l'exposer derrière Traefik (interne `.lab` ou public `.fr` + CrowdSec).
## Carte de bout en bout
```mermaid
%%{init: {'theme': 'base'}}%%
flowchart TB
classDef step fill:#2563eb,stroke:#1e40af,color:#fff
classDef plat fill:#059669,stroke:#047857,color:#fff
classDef gitops fill:#7c3aed,stroke:#6d28d9,color:#fff
classDef run fill:#b45309,stroke:#92400e,color:#fff
REPO["1 · Dépôt Gitea
arcodange-org/‹app›"]:::step
DB["2 · factory/postgres/iac
base ‹app› + rôle ‹app›_role"]:::plat
VAULT["3 · tools/hashicorp-vault/iac
gitea_cicd_‹app› + policies ‹app› / ‹app›-ops"]:::plat
CONTENT["4·5·6 · chart/ + iac/ + .gitea/
push → CI build image & tofu apply"]:::step
ARGO["7 · factory/argocd/values.yaml
→ Application ArgoCD (ns ‹app›)"]:::gitops
POD["Runtime · Pod(SA ‹app›) → VSO → Vault
creds/‹app› → pgbouncer.tools → base ‹app›"]:::run
REPO --> DB
REPO --> VAULT
DB --> CONTENT
VAULT --> CONTENT
CONTENT --> ARGO
ARGO --> POD
```
## Ordre des opérations (le point le plus important)
> [!IMPORTANT]
> Les étapes ne sont pas interchangeables. Le rôle JWT de CI `gitea_cicd_` (étape 3) et le rôle Postgres `_role` (étape 2) doivent **exister avant** que la CI Terraform de l'app (étape 6 appliquant l'étape 5) ne s'exécute — sinon l'authentification Vault de la CI échoue, ou le module `app_roles` n'a pas de `_role` à qui rattacher les credentials dynamiques.
```
[01] Dépôt Gitea sous arcodange-org (hérite les secrets CI d'org)
│
├──> [02] factory/postgres/iac → base + _role + user_lookup()
│
└──> [03] tools/hashicorp-vault/iac → gitea_cicd_ (JWT CI) + policies / -ops
│ (02 et 03 indépendants entre eux, mais TOUS DEUX avant 05)
▼
[04+05+06] Contenu du dépôt : chart/ + iac/ + .gitea/workflows/ (+ Dockerfile)
│ push → CI « dockerimage » build l'image · CI « vault » applique iac/
│ → creds/ (rôle DB dynamique) + rôle K8s + secrets KV
▼
[07] factory/argocd/values.yaml → ArgoCD crée l'Application → déploie le chart dans le namespace
▼
Runtime : Pod(SA ) → VSO → VaultAuth(role ) → creds/
→ user PG dynamique héritant de _role → pgbouncer.tools → base
```
## Prérequis plateforme (déjà en place)
Ces fondations existent et ne sont **pas** à refaire pour chaque app :
| Brique | Où | Rôle |
|---|---|---|
| Mounts Vault `kvv2`, `postgres`, `transit`, auth `kubernetes` | [`tools/hashicorp-vault/iac/main.tf`](https://gitea.arcodange.lab/arcodange-org/tools/src/branch/main/hashicorp-vault/iac/main.tf) | Moteurs de secrets + auth K8s |
| Connexion Vault→Postgres (via `pgbouncer.tools`, user `credentials_editor`) | idem | Permet à Vault d'émettre des users PG dynamiques |
| Rôle JWT de bootstrap `gitea_cicd` + app OAuth2 Gitea (`gitea_app_id`) | [`gitea_oidc_auth.yml`](https://gitea.arcodange.lab/arcodange-org/factory/src/branch/main/ansible/arcodange/factory/playbooks/tools/roles/hashicorp_vault/tasks/gitea_oidc_auth.yml) | Échange OIDC Gitea → JWT Vault dans la CI |
| Bot `tofu_module_reader` (clé SSH dans `kvv1/gitea/tofu_module_reader`) | [`factory/iac/gitea_tofu_ci_user.tf`](https://gitea.arcodange.lab/arcodange-org/factory/src/branch/main/iac/gitea_tofu_ci_user.tf) | Laisse la CI cloner le module partagé `tools` en SSH |
| Secrets Actions d'organisation (`HOMELAB_CA_CERT`, `vault_oauth__sh_b64`, `PACKAGES_TOKEN`) | org Gitea `arcodange-org` | Hérités par tout dépôt de l'org |
## Index des étapes
| # | Page | Ce qu'on y fait | Statut |
|---|---|---|---|
| — | [Conventions de nommage](conventions.md) | Le nom `` réutilisé à l'identique partout (à lire en premier) | ✅ |
| 01 | [Dépôt Gitea](01-gitea-repo.md) | Créer le dépôt sous `arcodange-org` + squelette | ✅ |
| 02 | [Base de données](02-database.md) | `factory/postgres/iac` → base `` + rôle `_role` | ✅ |
| 03 | [Vault plateforme](03-vault-platform.md) | `tools/hashicorp-vault/iac` → `gitea_cicd_` + policies | ✅ |
| 04 | [Chart Helm](04-helm-chart.md) | Le chart de l'app (DB via pgbouncer, secrets VSO, ingress) | ✅ |
| 05 | [Terraform de l'app](05-app-terraform.md) | `iac/` → module `app_roles` (creds dynamiques + rôle K8s) | ✅ |
| 06 | [Workflows CI](06-ci-workflows.md) | `.gitea/workflows/` : `tofu apply` + build image | ✅ |
| 07 | [Enregistrement ArgoCD](07-argocd-register.md) | `factory/argocd/values.yaml` → Application + déploiement | ✅ |
| 08 | [Checklist](08-checklist.md) | Récapitulatif ordonné + definition of done | ✅ |
## Légende de statut
✅ actif · 🟡 dégradé/beta · 🔴 critique/EOL · ⚠️ problème connu · ❌ désactivé
## Comment éditer ce runbook
1. **Ajouter une page** → la créer depuis le template tree-docs adéquat **et** ajouter sa ligne dans l'index ci-dessus.
2. **Garder les liens croisés bidirectionnels** → toute dépendance citée dans une page (`Upstream`/`Downstream`) doit avoir sa réciproque sur l'autre page.
3. **Mettre à jour `Last Updated:`** ci-dessus après tout changement de structure.
4. Les exemples cités (`erp`, `webapp`) sont vivants : revérifier les snippets contre le code réel avant de s'y fier aveuglément.