# Leave Bastide, towards Vercel, Supabase or elsewhere

The exit archive is a right, not a tier feature: it is produced at no cost and with no condition, including during a billing dispute and thirty days after termination. It contains no proprietary format: each file opens with a public-domain tool, which its `LISEZMOI.md` names. This page produces the archive, checks it, restores it on your own PostgreSQL, then says what is replayed at Vercel and at Supabase.

## Before you start

- An RSA key pair, which you keep: secrets never leave in clear, and the archive is refused without a valid public key, even when there is no secret.
- During the beta, producing the archive is an operator action (`pnpm exporter-projet`), which reads the platform with the API's ordinary configuration. No registry operation serves it yet: ask the operator.

## 1. Produce the archive

```
openssl genrsa -out cle-privee.pem 3072
openssl rsa -in cle-privee.pem -pubout -out cle.pem
pnpm exporter-projet --projet <prj_…> --cle-publique cle.pem --sortie ./archive
```

The exit code gives the outcome: `0` complete archive, `1` refusal (key missing, unknown project, unreadable), `3` archive written but incomplete: omitted secrets and warnings are listed, named, never passed over in silence. The download link of a hosted archive is valid for 7 days and resumes after an interruption (byte range, `curl -C -`).

## 2. What the archive contains

Nine items: `code/` (sources as deployed), `database/` (`schema.sql` and one CSV per table), `storage/` (objects, original bytes), `auth/utilisateurs.json`, `config/configuration.json`, `secrets/secrets.json` (encrypted), `logs/journaux.ndjson`, `MANIFEST.json` (SHA-256 of each file) and `LISEZMOI.md`.

## 3. Check and restore on your infrastructure

Nothing from Bastide is needed: PostgreSQL 14 or later, `psql`, `jq` and `sha256sum`. From the root of the archive, the integrity check:

```
cd archive
jq -r '.fichiers[] | "\(.sha256)  \(.chemin)"' MANIFEST.json | sha256sum -c -
```

The complete restore procedure (schema, loading the tables with constraints lifted during the load, objects, row recount) is the `sh restauration` block of the archive's `LISEZMOI.md`: follow it as is, it is what the quarterly restore exercise (`pnpm exercice-restauration`) runs on a fresh infrastructure. If the schema cites a role absent from your PostgreSQL, `psql` stops naming the role: create it (`create role <name>;`) and rerun the schema step.

Secrets are decrypted separately: each entry carries `cle_enveloppee` (an AES-256 key wrapped in RSA-OAEP SHA-256 for your public key), `iv`, `etiquette` (GCM) and `chiffre`, in base64. Variable names are readable, values never are in the archive.

## 4. Replay at Supabase

The restored database is an ordinary PostgreSQL: load `database/schema.sql` and the CSVs into the target project with `psql`. The objects of `storage/` go back into buckets of your choice. `auth/utilisateurs.json` is read with `jq` and imported into the identity system of your choice. The Bastide-specific gaps that play on exit: roles carry the database name as a prefix (`LIM-11`), so reread the `grant` and `create policy` statements of the schema before replaying them; the row-level security policies are in the schema.

## 5. Replay at Vercel

The `code/` folder is an ordinary repository: push it to Git and connect it to Vercel. `config/configuration.json` and the repository's `glowsoft.json` are read with `jq`. No converter from `glowsoft.json` to `vercel.json` is shipped: rewrite the redirects, rewrites and headers in `vercel.json`. Sensitive variables are decrypted (step 3) then entered at Vercel.

## Known incompatibilities

- No restore of a database from a backup is in the MCP tool catalogue: the exit goes through the archive, not through a database rollback.
- `secrets/secrets.json` is encrypted for your public key: losing the private key means losing the values. A secret the platform could not open is named under `ARCHIVE INCOMPLÈTE`, never silently omitted (exit code `3`).
- The legacy `anon` and `service_role` keys of an imported project (`LIM-09`) stop being accepted twelve months after the import, and are valid only at Bastide: on exit, use the target platform's keys.
- Bastide-specific extensions and settings do not move: realtime broadcast from the database (`realtime.diffuser_les_changements`, `LIM-08`) is a Bastide function, to replace at the destination platform.
- The restore exercise by a person outside the team, on an infrastructure that is not ours (EX-MIG-200), is still to be carried out: the automated exercise settles the part a machine can judge.

See also: [Migrate from Vercel](from-vercel.md), [Migrate from Supabase](from-supabase.md), [Restore](restore.md).
