# Cadriciels

Bastide reconnaît la plupart des applications web sans fichier de configuration : il détecte le cadriciel, compose l'image et la sert. Cette page dit quels cadriciels sont pris en charge et à quel engagement, comment se passe la détection, quand fournir votre propre `Dockerfile`, quel contrat d'exécution votre application doit tenir, et comment déclarer plusieurs services dans un projet.

## Trois rangs de prise en charge

| Rang | Engagement | Cadriciels | Reconnu aujourd'hui |
| --- | --- | --- | --- |
| **A, vendu** | Gabarit écrit et maintenu par Glowsoft, suite de conformité à chaque version, taux de réussite publié, régression bloquante. | Next.js (16.2 et au-delà), Nuxt 4, SvelteKit 2, Astro 5, React Router 7 / Remix, Vite (application monopage), export statique, Node générique (Express, Fastify, Hono, NestJS) | oui |
| **B, supporté** | Gabarit écrit, tests d'intégration, correction sous 30 jours, sans engagement de parité fonctionnelle. | Python ASGI et WSGI (FastAPI, Django, Flask), Go, générateurs statiques (Hugo, Docusaurus, VitePress), PHP 8.3 et au-delà (Symfony, Laravel) | en partie : Python et Go |
| **C, au mieux** | Repli généraliste (Railpack), aucun engagement, avertissement à la détection. | Ruby, Rust, Bun, Deno, Java | non |

La matrice publiée, avec le taux de réussite de chaque cadriciel du rang A et les conditions de sa mesure, est engendrée depuis le code : elle fait foi. Les générateurs statiques et PHP du rang B ne sont pas encore reconnus. Au rang C, seul un dépôt Deno a été mesuré par le repli ; Ruby, Rust, Bun et Java ne le sont pas encore.

### Next.js

- À partir de la 16.2, l'application passe par l'adaptateur de Bastide : serveur autonome, actifs immuables servis à part, manifeste de déploiement.
- Avant la 16.2, elle est assemblée par OpenNext ; si l'assemblage échoue, elle est servie comme une application Node (`next start`). Sous OpenNext, `revalidateTag` ne vaut que pour l'instance qui l'appelle.
- Il n'y a pas de runtime d'isolats en périphérie : l'intergiciel et les routes `runtime = 'edge'` s'exécutent dans le runtime Node du conteneur.

## La détection

À chaque construction, la plateforme lit les fichiers de la racine de construction (la « Racine du projet » des réglages, ou la racine du dépôt) sans exécuter aucun script du dépôt. Elle essaie les détecteurs du plus spécifique au plus général : un projet Next.js contient React, un projet Astro contient Vite, et l'ordre évite un plan qui marcherait presque. Le cadriciel détecté, l'étage de construction et l'empreinte du plan se lisent dans `buildPlan` de `deployment_read`, et sous « Détails techniques » de l'écran **Déploiement**.

L'image se construit à l'un de trois étages, dans cet ordre :

1. **Votre `Dockerfile`**, s'il est à la racine de construction : il est construit tel quel.
2. **L'image composée par la plateforme**, depuis le cadriciel détecté.
3. **Le repli généraliste**, pour un dépôt qu'aucun détecteur ne reconnaît.

### Les versions d'exécution

| Exécution | Versions servies | Défaut | Lue dans |
| --- | --- | --- | --- |
| Node | 20, 22, 24 | 22 | `engines.node` du `package.json` |
| Python | 3.11, 3.12, 3.13 | 3.12 | `.python-version`, puis `requires-python` de `pyproject.toml` |
| Go | 1.22, 1.23, 1.24 | 1.23 | la ligne `go` de `go.mod` |

Pour Node, toute forme qui nomme un seul majeur est reconnue : `20`, `20.x`, `^20.0.0`, `~20.11`, `20.11.1` donnent Node 20. Une plage ouverte (`>=20`) ne l'est pas, et le défaut s'applique. Un projet qui ne déclare rien garde la version qu'il a reçue à sa création : aucune montée de version majeure n'a lieu sans votre action. Si cette version quitte le catalogue, la construction est refusée plutôt que montée en silence.

Le gestionnaire de paquets (pnpm, yarn, npm ou bun) se déduit du dépôt. Pour pnpm et yarn moderne, la version est celle que déclare `packageManager`.

## Fournir votre Dockerfile

Un fichier `Dockerfile` à la racine de construction est utilisé tel quel, sans réécriture : la plateforme le construit ou le refuse, jamais entre les deux. Un refus cite le numéro de ligne, l'instruction et le motif. La politique est une liste blanche :

- Instructions admises : `FROM`, `ARG`, `RUN`, `COPY`, `ADD`, `CMD`, `ENTRYPOINT`, `ENV`, `EXPOSE`, `WORKDIR`, `USER`, `LABEL`, `SHELL`, `STOPSIGNAL`, `HEALTHCHECK`, `MAINTAINER`. `VOLUME` et `ONBUILD` sont refusées.
- Directives `# syntax=` et `# escape=` refusées ; blocs « heredoc » non construits (une commande sur plusieurs lignes avec `\` reste admise).
- `FROM --platform` : `linux/amd64`, `$BUILDPLATFORM` ou `$TARGETPLATFORM` seulement.
- `RUN --network` : `none` seulement. `RUN --mount` : `tmpfs` et `bind` seulement ; `cache`, `secret` et `ssh` sont refusés.
- Images de base tirées de `docker.io`, `ghcr.io`, `gcr.io`, `mcr.microsoft.com`, `quay.io`, `public.ecr.aws` ou `registry.k8s.io`. Le réglage « Registres d'images admis » du projet resserre cette liste.
- 256 Kio, 4 000 lignes et 32 Kio par ligne logique au plus ; UTF-8 valide.
- L'image doit déclarer `CMD` ou `ENTRYPOINT`, viser Linux, et ne pas déclarer `/` comme volume.

Avec votre `Dockerfile`, la plateforme ne devine pas le port : déclarez-le par `port` dans `glowsoft.json`. Sans déclaration, elle prend 3000, et le dit dans l'événement du déploiement.

La plateforme n'ajoute rien à votre fichier : ni `ENV PORT`, ni sonde, ni compte. Les contraintes d'exécution ci-dessous s'appliquent en revanche à tout conteneur : prévoyez une image qui fonctionne sous un compte non root et sur une racine en lecture seule.

## Le contrat d'exécution

Toute image, composée ou fournie, doit tenir ce contrat.

| Exigence | Détail |
| --- | --- |
| Écouter sur `PORT` | La plateforme pose la variable `PORT`. L'image composée la fixe à 3000 (8080 pour un site statique) ; avec une sonde déclarée, `PORT` vaut le port sondé. N'écrivez pas de port en dur. |
| Démarrer seul | Un `CMD` ou un `ENTRYPOINT`. `NODE_ENV` et `PORT` sont fournis par la plateforme. |
| S'arrêter sur `SIGTERM` | À l'arrêt, le conteneur reçoit `SIGTERM` et dispose de 30 secondes pour finir ses requêtes avant d'être tué. Un `STOPSIGNAL` peut choisir `SIGQUIT`, `SIGWINCH`, `SIGINT`, `SIGHUP`, `SIGUSR1` ou `SIGUSR2`, écrit par son nom. |
| Ne pas écrire hors de `/tmp` | Tout conteneur tourne sous l'UID 10000, racine en lecture seule, `/tmp` en mémoire, sans aucune capacité Linux, y compris avec votre `Dockerfile`. |

### La sonde de santé

Il n'y a pas de sonde par défaut. Sans sonde déclarée, « En ligne » signifie « le conteneur tourne ». Pour qu'un déploiement ne bascule que lorsque l'application répond, déclarez-en une dans `glowsoft.json` :

```json
{
  "version": 1,
  "probe": { "path": "/sante", "startupBudgetSeconds": 120 }
}
```

`path` est le chemin que la plateforme interroge en HTTP sur le port de l'application ; il commence par `/` et ne porte ni espace ni métacaractère. Le chemin est libre : `/sante`, `/health`, `/api/ping`. La sonde attend une réponse de succès, interroge toutes les dix secondes avec un délai de deux secondes, et le budget de démarrage va de 60 à 180 secondes (60 par défaut). Au-delà, le déploiement échoue et l'ancien continue de servir.

## Plusieurs services par projet

Par défaut, un projet a un seul service web, sans nom. `services` dans `glowsoft.json` en déclare plusieurs, qui partagent la même image et se joignent par leur nom sur le réseau privé du projet.

| Genre | Ce qu'il fait |
| --- | --- |
| `web` | Écoute, et reçoit le trafic de l'adresse du projet. Exactement un par déclaration. |
| `worker` | N'écoute pas ; démarre par `<gestionnaire> run <start>`, où `start` est le nom d'un script du `package.json`, jamais une commande. |
| `statique` | Sert les fichiers d'un répertoire produit par la construction (`directory`), sur le réseau privé seulement. |
| `cron` | Un conteneur par exécution, à l'horaire déclaré : voir [Tâches planifiées](cron.md). |

```json
{
  "version": 1,
  "services": [
    { "name": "web", "type": "web" },
    { "name": "ouvrier", "type": "worker", "start": "start:worker" }
  ]
}
```

Un nom de service commence par une lettre minuscule, puis jusqu'à trente lettres, chiffres ou tirets, et deux services ne portent pas le même nom. Un `worker` n'est démarré que lorsque la plateforme compose elle-même l'image Node : pas avec un `Dockerfile` fourni, un export statique, Python, Go ou le repli.

| Palier | Services par projet |
| --- | --- |
| Découverte | 1 |
| Standard | 10 |
| Pro | 25 |
| Souverain | négocié |

Le nombre d'exemplaires du service de production (de 1 à 10) se règle dans **Réglages** du projet. La console ne montre pas encore la liste des services d'une release.

## Erreurs fréquentes

| Code | Remède |
| --- | --- |
| `framework_not_detected` | Ni un détecteur ni le repli n'ont tiré de plan. Fournir un `Dockerfile`, ou corriger la « Racine du projet ». |
| `build_version_gelee_indisponible` | La version gelée du projet a quitté le catalogue : déclarer une version servie dans le dépôt (`engines.node` pour Node). |
| `image_sans_demarrage` | Ajouter `CMD` ou `ENTRYPOINT` au `Dockerfile`. |
| `image_signal_darret` | N'employer qu'un signal de la liste servie. |
| `service_hors_gabarit_node` | Un `worker` exige l'image Node composée par la plateforme. |
| `declaration_refusee` | Plus de services que le palier n'en permet, ou forme invalide de `glowsoft.json`. |

Un déploiement qui reste en « Mise en service » puis échoue sur la sonde vient le plus souvent d'une application qui n'écoute pas sur `PORT`, ou d'un `Dockerfile` dont le port n'est pas déclaré.

Voir aussi : [Constructions](builds.md), [Git et déploiement automatique](git.md), [Déployer](deploy.md), [Tâches planifiées](cron.md), [Environnements et variables](environments.md).
