3 schémas PostgreSQL pour une app propre — structurer Supabase dès le départ
Quand tu démarres un projet, la tentation est grande de tout mettre dans le schéma public de PostgreSQL. Une table ici, une autre là, et en trois semaines tu te retrouves avec 40 tables mélangées sans aucune logique.
J'ai décidé très tôt de structurer TAMSIV avec trois schémas séparés.
Les trois schémas
privat— Toutes les données personnelles : tâches, mémos, événements calendrier, profils utilisateur, pièces jointescollaborative— Tout ce qui touche aux groupes : membres, rôles, tâches partagées, checklists de groupegamification— Les stats, badges, streaks, challenges quotidiens, historique des points
Pourquoi privat et pas private ? Parce que private est un mot réservé en SQL. J'ai appris ça à mes dépens après une migration ratée.
Pourquoi séparer ?
1. La lisibilité. Quand je fais SELECT * FROM privat.tasks, je sais immédiatement que c'est une donnée personnelle.
2. La sécurité. Les politiques RLS sont plus faciles à raisonner quand les tables sont groupées par domaine. Les règles du schéma privat sont simples : tu ne vois que tes données. Celles du schéma collaborative sont plus complexes : tu vois les données des groupes dont tu es membre, selon ton rôle.
3. L'évolution. Quand j'ai ajouté la gamification trois mois après le début du projet, j'ai créé un nouveau schéma sans toucher aux deux autres. Zéro risque de casser l'existant.
Le cauchemar des politiques RLS
Supabase utilise RLS pour sécuriser l'accès aux données. Le principe est simple : chaque table a des règles qui déterminent qui peut lire, écrire, modifier, supprimer. En pratique, c'est un labyrinthe.
Au total, le projet compte plus de 30 politiques RLS. Chacune testée individuellement.
Les conventions de nommage
J'ai adopté des conventions strictes : tables en snake_case au pluriel, colonnes en snake_case, paramètres RPC avec préfixe p_. Ce préfixe p_ évite les collisions avec les noms de colonnes dans les requêtes. Le jour où ton paramètre user_id entre en conflit avec la colonne user_id, tu comprends pourquoi.
Cette structure m'a fait gagner un temps considérable sur la suite. Chaque nouvelle feature trouve sa place naturellement.