Migration Supabase → Kuunda Cloud

Auth, SDK, cutover. Export SQL et assistant console : Importer vers Kuunda Cloud (schema.sql + data.sql).

1. Vue d’ensemble

SupabaseKuunda Cloud
Schéma publicSchéma tenant proj_{uuid32hex}
https://{ref}.supabase.cohttps://{ref8}.kuunda-cloud.com
@supabase/supabase-js@kuunda/kuunda-js
Auth + Storage dans la même DBAuth 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.

SujetRè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.usersPas 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 SQLLes commentaires et littéraux chaîne ne sont pas traités comme du SQL exécutable.
Dumps schema.sqlPré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.

RessourceLimite assistant
Fichier SQL~20 Mo
Comptes Auth2 000
Storage50 buckets, 2 000 fichiers, 50 Mo/fichier
Tables inventoriées500

Au-delà : découper les exports et répéter les imports.

3. Inventaire avant migration

ComposantMigration
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

  1. Console Kuunda → Nouveau projet
  2. 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

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

  1. Carte Export BaaS (schéma public)
  2. Coller l’URI Postgres Supabase (optionnel, pour le comptage)
  3. Schéma source : public
  4. 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éesSessions / 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

ChampValeur
URL Storagehttps://{ref}.supabase.co
Clé service_roleSettings → 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.

  1. Étape Script : uploader schema.sql
  2. Transformer → proj_…
  3. Appliquer sur Kuunda
  4. Revenir à Source → Importer auth.users
  5. Répéter Script / Transformer / Appliquer avec data.sql
  6. Source → Importer Storage
  7. 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

MessageCause / 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 existsImport partiel — supprimez le type ou la table concernée, ou repartez d’un projet Kuunda vierge.
function gen_random_uuid() does not existInstallez 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 publicRetirez 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 MoDé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émentAction
Edge FunctionsRécupérer le code → redéployer dans Kuunda → Functions
SecretsRecopier manuellement
Webhooks, pg_cron, VaultRecréer dans Kuunda

10. Adapter l’application

Variables d’environnement

Avant (Supabase)Après (Kuunda)
NEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_KUUNDA_URL = https://{ref8}.kuunda-cloud.com
NEXT_PUBLIC_SUPABASE_ANON_KEYNEXT_PUBLIC_KUUNDA_ANON_KEY = kuunda_anon_…
SUPABASE_SERVICE_ROLE_KEYkuunda_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

Compatibilité API

APIStatus
.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

  1. Valider import DB (rapport comptage OK)
  2. Tester login email + OAuth (UUID identique pour users importés)
  3. Tester Storage et RLS
  4. Déployer l’app avec @kuunda/kuunda-js
  5. Ajouter callback OAuth Kuunda (conserver Supabase pour rollback)
  6. Maintenance : stopper écritures Supabase, import delta si besoin
  7. 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

TestRésultat attendu
Comptages tablesSource = Kuunda
Login email/passwordMême mot de passe, session active
Login OAuthMême UUID qu’avant
RLSanon bloqué, authenticated OK
StorageUpload + download OK
RealtimeÉvénement reçu
RPC.rpc('ma_fonction') retourne les données

13. Ordre des opérations

  1. Créer projet Kuunda + noter ref, schéma, clés API
  2. Configurer Auth (URLs + providers OAuth)
  3. Installer les extensions PostgreSQL requises (pgcrypto, etc.)
  4. Exporter Supabase → schema.sql + data.sql
  5. Kuunda Import : analyser la source
  6. Transformer + Appliquer schema.sql
  7. Importer auth.users
  8. Transformer + Appliquer data.sql
  9. Importer Storage
  10. Rapport source ↔ Kuunda
  11. Sync Realtime si besoin
  12. Redéployer Edge Functions + secrets
  13. Adapter l’app → @kuunda/kuunda-js
  14. Tests complets
  15. Cutover production

14. Ce qui ne migre pas automatiquement

SupabaseAction requise
Edge FunctionsRedéployer sur Kuunda
Database WebhooksRecréer (triggers + HTTP)
Vault / secretsRe-saisir manuellement
Extensions absentesDatabase → Extensions
Cron jobsJob externe ou cron VPS
URLs Storage en durMettre à jour code et base
SMTP / templates emailAuth → Emails

Ouvrir la console