# Projets

> Grouper des services, leur donner un réseau privé, lire leur dépense.

Un projet réunit des services et leur donne un **réseau privé** : ils se joignent entre
eux par leur alias, et rien d'autre ne les joint. Tout service appartient à un projet ;
sans précision, il rejoint le projet par défaut du compte.

## Lister

```http
GET /api/projects
```

```json
[
  {
    "id": "cmu5xje0s0001itlh3jg2pptf",
    "name": "CodexaStudio",
    "createdAt": "2026-09-17T19:35:43.037Z",
    "resourceCount": 2
  }
]
```

## Créer, renommer, supprimer

```http
POST   /api/projects            { "name": "Production" }
PATCH  /api/projects/{id}       { "name": "Prod" }
DELETE /api/projects/{id}
```

Le nom fait 60 caractères au maximum et doit être unique sur ton compte.

<Note>
Supprimer un projet ne supprime pas ses services : ils redeviennent autonomes et
rejoignent le projet par défaut. Le projet par défaut, lui, ne se supprime pas.
</Note>

## Lire un projet

```http
GET /api/projects/{id}
```

Rend le projet, plus `resources` : ses services dans la forme abrégée de
[`GET /api/resources`](/api/services#lister).

## La dépense du projet

```http
GET /api/projects/{id}/consommation
```

```json
{
  "id": "cmu5xje0s0001itlh3jg2pptf",
  "name": "CodexaStudio",
  "range": 30,
  "totalCents": 112,
  "days": [{ "date": "2026-09-18", "totalCents": 4 }],
  "services": [
    {
      "id": "cmu5xje1k0003itlhpkwwfq66",
      "name": "crm",
      "family": "APP",
      "productName": "Applications",
      "detail": "3 vCPU, 2 Go, 10 Go",
      "totalCents": 68,
      "parts": [
        { "label": "Processeur", "cents": 35 },
        { "label": "Mémoire", "cents": 27 },
        { "label": "Disque", "cents": 6 }
      ]
    }
  ]
}
```

La somme des `parts` fait exactement le `totalCents` du service : l'arrondi est absorbé
par la dernière part, jamais réparti au hasard. Un service sans dépense sur la fenêtre
rend `parts` vide plutôt que des parts à zéro.

## Le graphe

```http
GET /api/projects/{id}/graphe
```

```json
{
  "id": "cmu5xje0s0001itlh3jg2pptf",
  "name": "CodexaStudio",
  "nodes": [
    {
      "id": "cmu5z0wnl0001ith2rbk5ryeh",
      "name": "crm-db",
      "family": "APP",
      "alias": "crm-db",
      "subtitle": "0.0.0.0:30015",
      "status": "ACTIVE",
      "state": "running",
      "capabilities": ["logs", "powerSignals", "variables"],
      "diskBytes": 0,
      "position": { "x": 0, "y": 0 }
    }
  ],
  "edges": [
    { "from": "cmu5xje1k0003itlhpkwwfq66", "to": "cmu5z0wnl0001ith2rbk5ryeh", "through": ["DATABASE_URL"] }
  ]
}
```

`position` est la disposition enregistrée du canevas de l'espace client ; un nœud jamais
déplacé est en `0,0`. Tu peux l'ignorer.

Les liens ne sont pas déclarés : ils sont **déduits des variables**. Un service qui écrit
`${crm-db.URL}` dans son environnement produit une arête vers `crm-db`, et `through` dit
par quelle variable. C'est la vue qu'affiche le canevas de l'espace client.
