BaliseTonSite

Bonnes pratiques et production

Architecture, migrations, monitoring, types auto-générés et checklist de mise en production.

10.1Migrations avec le CLI

Ne modifie jamais le schéma directement dans le dashboard en production. Utilise les migrations SQL versionnées :

Workflow avec les migrationsbash
# Créer une nouvelle migration
supabase migration new add-articles-table
# → supabase/migrations/20240101120000_add-articles-table.sql

# Écrire le SQL de la migration
# (le fichier est créé vide, à toi de le remplir)

# Appliquer les migrations en local
supabase db reset  # Recrée la DB locale depuis les migrations

# Pousser les migrations en production
supabase db push
supabase/migrations/20240101120000_add-articles-table.sqlbash
-- Migration : créer la table articles
CREATE TABLE IF NOT EXISTS articles (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL,
  title TEXT NOT NULL,
  content TEXT,
  published BOOLEAN DEFAULT false,
  created_at TIMESTAMPTZ DEFAULT now()
);

-- RLS
ALTER TABLE articles ENABLE ROW LEVEL SECURITY;

CREATE POLICY "users can read published articles"
ON articles FOR SELECT
USING (published = true);

CREATE POLICY "users can manage own articles"
ON articles FOR ALL
USING (auth.uid() = user_id);

10.2Types TypeScript auto-générés

Générer les types depuis le schémabash
# Générer les types TypeScript
supabase gen types typescript --linked > lib/types/database.ts

# Ou depuis une DB locale
supabase gen types typescript --local > lib/types/database.ts
lib/types/database.ts (extrait généré)typescript
export type Database = {
  public: {
    Tables: {
      articles: {
        Row: {
          id: string
          user_id: string
          title: string
          content: string | null
          published: boolean
          created_at: string
        }
        Insert: {
          id?: string
          user_id: string
          title: string
          content?: string | null
          published?: boolean
          created_at?: string
        }
        Update: {
          id?: string
          user_id?: string
          title?: string
          content?: string | null
          published?: boolean
          created_at?: string
        }
      }
    }
  }
}
Utiliser les types dans le clienttypescript
import { createBrowserClient } from '@supabase/ssr'
import type { Database } from '@/lib/types/database'

export function createClient() {
  return createBrowserClient<Database>(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
  )
}

// Maintenant TypeScript connaît le schéma :
const { data } = await supabase.from('articles').select('*')
// data est typé : Database['public']['Tables']['articles']['Row'][]

10.3Architecture recommandée

Structure de projet Supabase + Next.jsbash
projet/
├── supabase/
   ├── config.toml              # Config du projet Supabase
   ├── migrations/              # Migrations SQL versionnées
   ├── 20240101_init.sql
   └── 20240115_add_articles.sql
   ├── functions/               # Edge Functions
   └── stripe-webhook/
       └── index.ts
   └── seed.sql                 # Données de test

├── lib/
   ├── supabase/
   ├── client.ts            # createBrowserClient
   └── server.ts            # createServerClient
   └── types/
       └── database.ts          # Types auto-générés

├── middleware.ts                 # Refresh JWT
└── .env.local                   # Variables d'environnement

10.4Sécurité en production

ChecklistDétail
RLS activé sur toutes les tablesJamais de table sans RLS en production
anon key = côté client uniquementElle est publique, RLS la protège
service_role key = serveur uniquementBypass RLS, ne jamais exposer côté client
Tester les policiesVérifier qu'un user ne peut pas lire/modifier les données d'un autre
Email confirmé obligatoireDashboard → Auth → Settings → Confirm email
Rate limitingAuth rate limits dans les settings du dashboard

10.5Monitoring et logs

Dashboard Supabasebash
Dashboard :
├── Logs API Logs      # Toutes les requêtes API
├── Logs Auth Logs     # Connexions, inscriptions, erreurs
├── Logs Database Logs # Requêtes SQL lentes
├── Reports              # Usage, quotas, alertes
└── SQL Editor           # Exécuter des requêtes manuelles
Logger les erreurs côté applicationtypescript
// Wrapper pour logger les erreurs Supabase
async function safeQuery<T>(
  query: Promise<{ data: T | null; error: { message: string } | null }>
): Promise<T | null> {
  const { data, error } = await query

  if (error) {
    console.error('[Supabase Error]', error.message)
    return null
  }

  return data
}

// Utilisation
const articles = await safeQuery(
  supabase.from('articles').select('*').eq('published', true)
)

10.6Environnements séparés

Deux projets Supabasebash
# Bonne pratique : un projet par environnement
Supabase Dashboard :
├── mon-app-dev    # Développement (données de test)
└── mon-app-prod   # Production (données réelles)

# .env.local (dev)
NEXT_PUBLIC_SUPABASE_URL=https://xxxx-dev.supabase.co

# .env.production (prod)
NEXT_PUBLIC_SUPABASE_URL=https://xxxx-prod.supabase.co

# Les migrations sont les mêmes, appliquées aux deux
supabase link --project-ref projet-dev
supabase db push

supabase link --project-ref projet-prod
supabase db push

Verifie tes acquis

5 questions pour valider ce chapitre

1. Pourquoi utiliser des migrations SQL plutot que modifier le schema dans le dashboard ?

Valide et sauvegarde ce chapitre

Ne perds pas le fil de ton apprentissage. Chaque QCM terminé sauvegarde ton score. Crée ton profil gratuitement pour débloquer toutes les évaluations du site et retrouver tes résultats plus tard.

Commencer l'aventure
Déjà membre ?Connecte-toi