Migration Supabase → Kuunda Cloud
Auth, SDK, cutover. Export SQL et assistant console : Importer vers Kuunda Cloud (schema.sql + data.sql).
1. Vue d’ensemble
| Supabase | Kuunda Cloud |
|---|---|
Schéma public | Schéma tenant proj_{uuid32hex} |
https://{ref}.supabase.co | https://{ref8}.kuunda-cloud.com |
@supabase/supabase-js | @kuunda/kuunda-js |
| Auth + Storage dans la même DB | Auth séparé ; helpers auth.uid() recréés dans le tenant |
Assistant d’import : Projet → Réglages → Import données (https://app.kuunda-cloud.com).
Éditeur SQL (schéma projet)
L’éditeur SQL et POST /migrate s’exécutent dans le schéma projet proj_…, pas dans public — comme tout dump Postgres (schéma source public). L’assistant d’import réécrit le schéma ; coller un script non adapté dans l’éditeur échoue souvent.
| Sujet | Règle Kuunda |
|---|---|
Schéma public. | Retirez le préfixe public. Le search_path de session est déjà le schéma projet. Omettez SET search_path = public. |
auth.users | Pas de SELECT sur le catalogue Auth (base séparée). Helpers : auth.uid(), auth.email(), auth.role(), auth.jwt(). Métadonnées d’inscription : auth.jwt() -> 'user_metadata'. Dans l’éditeur, ces fonctions sont NULL (pas de JWT utilisateur) ; elles s’évaluent via l’API REST / RPC authentifiée. |
| Commentaires SQL | Les commentaires et littéraux chaîne ne sont pas traités comme du SQL exécutable. |
| Dumps schema.sql | Préférez Projet → Réglages → Import données : réécriture public. → proj_…, conservation de auth.uid(), ignore des FK auth.users. |
Exemple compatible éditeur
CREATE OR REPLACE FUNCTION ensure_user_profile(
p_email text DEFAULT NULL
)
RETURNS void
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
DECLARE
v_uid uuid := auth.uid();
BEGIN
IF v_uid IS NULL THEN RAISE EXCEPTION 'Not authenticated'; END IF;
INSERT INTO profiles (id, email)
VALUES (
v_uid,
COALESCE(NULLIF(TRIM(p_email), ''), COALESCE(auth.email(), ''))
)
ON CONFLICT (id) DO NOTHING;
END;
$$;
GRANT EXECUTE ON FUNCTION ensure_user_profile(text) TO authenticated;2. Prérequis
Sur votre PC : terminal (PowerShell ou bash) et client PostgreSQL avec pg_dump.
Sur Supabase : mot de passe de la base (bouton Connect ou Settings → Database).
Sur Kuunda : compte sur https://app.kuunda-cloud.com/register.
| Ressource | Limite assistant |
|---|---|
| Fichier SQL | ~20 Mo |
| Comptes Auth | 2 000 |
| Storage | 50 buckets, 2 000 fichiers, 50 Mo/fichier |
| Tables inventoriées | 500 |
Au-delà : découper les exports et répéter les imports.
3. Inventaire avant migration
| Composant | Migration |
|---|---|
| Tables, vues, fonctions, triggers, RLS | ✅ Export SQL + assistant |
| Auth (email / mot de passe) | ✅ Bouton Import auth.users |
| OAuth (Google, GitHub…) | ⚠️ Reconfiguration des providers |
| Storage | ✅ Bouton Import Storage |
| Realtime | ✅ Sync automatique à l’import |
| Edge Functions | ❌ Redéploiement manuel |
| Webhooks DB, pg_cron, Vault | ❌ Recréation manuelle |
| Extensions PostgreSQL | ⚠️ Database → Extensions |
| SMTP / templates email | ❌ Auth → Emails |
4. Créer le projet Kuunda
- Console Kuunda → Nouveau projet
- Réglages → API — noter :
- URL :
https://xxxxxxxx.kuunda-cloud.com - Clé anon :
kuunda_anon_… - Clé service_role :
kuunda_service_…(serveur uniquement) - Schéma tenant :
proj_+ 32 caractères hex
- URL :
5. Configurer Auth (avant l’import des users)
Sur Supabase
Authentication → URL Configuration (Site URL, Redirect URLs) et Providers (Client ID / Secret OAuth).
Sur Kuunda
Auth → Providers : reprendre les mêmes URLs, activer les mêmes providers, enregistrer la nouvelle URI de callback affichée dans Kuunda.
Production SaaS : https://api.kuunda-cloud.com/auth/v1/callback. Mettre à jour chez Google / Apple. Conserver l’URI Supabase tant que le cutover n’est pas validé. Détail : Connexion Google (OAuth).
6. Exporter la base Supabase
Commandes, identifiants (URL / URI / mot de passe) et où les coller : page Import. Méthode : schema.sql puis data.sql via pg_dump sur l’hôte direct db.{ref}.supabase.co (pas le dump tout-en-un, pas le pooler transactionnel port 6543).
7. Importer dans Kuunda
URL : https://app.kuunda-cloud.com/{ref}/settings/import
Étape 1 — Source
- Carte Export BaaS (schéma public)
- Coller l’URI Postgres Supabase (optionnel, pour le comptage)
- Schéma source :
public - Analyser la source (comptage)
Étape 2 — Importer les comptes
Après schema.sql, étape Source → Importer auth.users
| Conservé | Non migré |
|---|---|
| UUID identiques, mots de passe bcrypt, métadonnées | Sessions / JWT Supabase, identités OAuth, comptes sans email |
Les utilisateurs devront se reconnecter. Au premier login OAuth, Kuunda lie le compte par email.
Étape 3 — Importer Storage
| Champ | Valeur |
|---|---|
| URL Storage | https://{ref}.supabase.co |
| Clé service_role | Settings → API → Legacy → service_role (eyJ…) |
Après data.sql, cliquer Importer Storage. Sans URL + clé : buckets vides seulement.
Étape 4 — Appliquer le SQL
Ordre : schema.sql → auth.users → data.sql → Storage. Détail des champs : page Import.
Avant le schéma : extensions requises (ex. pgcrypto, déjà CORE) via Database → Extensions.
- Étape Script : uploader schema.sql
- Transformer → proj_…
- Appliquer sur Kuunda
- Revenir à Source → Importer auth.users
- Répéter Script / Transformer / Appliquer avec data.sql
- Source → Importer Storage
- Rapport source ↔ Kuunda — comptages Source = Kuunda
Migré : tables, RLS (auth.uid()), fonctions, triggers, vues, sync Realtime. Ignoré dans le SQL : FK vers auth.users / storage.*, rôles Supabase, COMMENT ON SCHEMA, event triggers au niveau cluster (CREATE EVENT TRIGGER), CREATE EXTENSION bloquées (installer via l’UI Extensions).
Dépannage import SQL
| Message | Cause / action |
|---|---|
transaction is aborted (souvent sur la première instruction DDL) | Indique qu’une instruction précédente du même lot a échoué. Vérifiez la version du dashboard (correctif savepoint sur session_replication_role). En cas d’import partiel, supprimez l’objet en conflit puis réappliquez, par ex. DROP TYPE IF EXISTS proj_…mon_enum CASCADE; ou DROP TABLE IF EXISTS proj_…ma_table CASCADE; |
type … already exists | Import partiel — supprimez le type ou la table concernée, ou repartez d’un projet Kuunda vierge. |
function gen_random_uuid() does not exist | Installez pgcrypto (Database → Extensions) avant d’appliquer le schéma. CORE le fournit déjà sur Kuunda. |
permission denied for schema auth (CREATE POLICY) | Corrigé côté Kuunda : le rôle proj_…_owner reçoit USAGE/EXECUTE sur auth.uid() avant import. Mettez à jour le dashboard puis réappliquez le schéma. |
permission denied for schema public | Retirez public. et SET search_path = public. Le schéma projet est déjà le search_path. Ou passez par l’assistant d’import (réécriture automatique). |
Référence interdite … (auth.users) | Pas d’accès à auth.users. Utilisez auth.uid(), auth.email(), auth.role(), auth.jwt(). Un commentaire contenant auth.users n’est plus bloqué. |
| Fichier > ~20 Mo | Découpez (--schema-only + --data-only) ou migrations à distance par morceaux. |
8. Realtime
L’import ajoute les tables à la publication Realtime. Si des tables manquent : Console → Realtime → Synchroniser la publication.
9. Edge Functions, cron, secrets
| Élément | Action |
|---|---|
| Edge Functions | Récupérer le code → redéployer dans Kuunda → Functions |
| Secrets | Recopier manuellement |
| Webhooks, pg_cron, Vault | Recréer dans Kuunda |
10. Adapter l’application
Variables d’environnement
| Avant (Supabase) | Après (Kuunda) |
|---|---|
NEXT_PUBLIC_SUPABASE_URL | NEXT_PUBLIC_KUUNDA_URL = https://{ref8}.kuunda-cloud.com |
NEXT_PUBLIC_SUPABASE_ANON_KEY | NEXT_PUBLIC_KUUNDA_ANON_KEY = kuunda_anon_… |
SUPABASE_SERVICE_ROLE_KEY | kuunda_service_… — serveur uniquement |
SDK
import { createClient } from '@kuunda/kuunda-js';
const kuunda = createClient(
process.env.NEXT_PUBLIC_KUUNDA_URL!,
process.env.NEXT_PUBLIC_KUUNDA_ANON_KEY!,
{
dbSchema: 'proj_uuid32hexsanstirets',
projectRef: 'abcdef12',
}
);Points clés
- Clé anon → header
apikeyuniquement, pas enAuthorization: Bearer - Bearer = JWT de session Auth (posé par le SDK après login)
- OAuth →
@kuunda/kuunda-js+projectRef(provider: 'google'/github/ …). Sans SDK :custom:proj-{ref}-google(tirets), pasprovider=google. - Données RLS → charger après connexion
- Storage → mêmes noms de buckets qu’avant
Compatibilité API
| API | Status |
|---|---|
.from().select/insert/update/delete | ✅ |
.rpc() | ✅ |
.auth.signUp / signIn / signOut | ✅ |
.auth.signInWithOAuth | ✅ avec @kuunda/kuunda-js |
.storage.from() | ✅ |
| Realtime | ✅ |
| Edge Functions | ⚠️ Redéployer avant utilisation |
Différences SDK Auth
// getSession — synchrone
const session = kuunda.auth.getSession();
// getUser
const { data: user, error } = await kuunda.auth.getUser();
// onAuthStateChange — un seul argument
kuunda.auth.onAuthStateChange(({ event, session }) => { … });11. Cutover production
- Valider import DB (rapport comptage OK)
- Tester login email + OAuth (UUID identique pour users importés)
- Tester Storage et RLS
- Déployer l’app avec @kuunda/kuunda-js
- Ajouter callback OAuth Kuunda (conserver Supabase pour rollback)
- Maintenance : stopper écritures Supabase, import delta si besoin
- Basculer DNS / variables vers Kuunda
Import delta : ré-exporter les tables modifiées ou migrations à distance (POST /api/projects/{ref8}/migrate/service-role).
12. Validation finale
| Test | Résultat attendu |
|---|---|
| Comptages tables | Source = Kuunda |
| Login email/password | Même mot de passe, session active |
| Login OAuth | Même UUID qu’avant |
| RLS | anon bloqué, authenticated OK |
| Storage | Upload + download OK |
| Realtime | Événement reçu |
| RPC | .rpc('ma_fonction') retourne les données |
13. Ordre des opérations
- Créer projet Kuunda + noter ref, schéma, clés API
- Configurer Auth (URLs + providers OAuth)
- Installer les extensions PostgreSQL requises (pgcrypto, etc.)
- Exporter Supabase → schema.sql + data.sql
- Kuunda Import : analyser la source
- Transformer + Appliquer schema.sql
- Importer auth.users
- Transformer + Appliquer data.sql
- Importer Storage
- Rapport source ↔ Kuunda
- Sync Realtime si besoin
- Redéployer Edge Functions + secrets
- Adapter l’app → @kuunda/kuunda-js
- Tests complets
- Cutover production
14. Ce qui ne migre pas automatiquement
| Supabase | Action requise |
|---|---|
| Edge Functions | Redéployer sur Kuunda |
| Database Webhooks | Recréer (triggers + HTTP) |
| Vault / secrets | Re-saisir manuellement |
| Extensions absentes | Database → Extensions |
| Cron jobs | Job externe ou cron VPS |
| URLs Storage en dur | Mettre à jour code et base |
| SMTP / templates email | Auth → Emails |