Mes Recettes : créer un index de recettes moderne avec Blazor WebAssembly et Supabase

Formes abstraites colorées pour Mes Recettes (Blazor + Supabase)

Mes Recettes : créer un index de recettes moderne avec Blazor WebAssembly et Supabase

Partie 1 sur 3 de la série Mes Recettes : Partie 2 – Architecture · Partie 3 – Tests & Livraison | English

Pourquoi ce projet existe

Je voulais un moyen rapide et portable d’indexer mes recettes de livres de cuisine — relier auteurs, livres, pages, notes et évaluations — avec un minimum d’infrastructure backend. Plutôt que de monter une API personnalisée + une base de données, j’ai associé Blazor WebAssembly (C# dans le navigateur) à Supabase (PostgreSQL managé, Auth, Realtime, REST).

Objectifs :

  • Expérience single-page, navigation instantanée
  • Modèles fortement typés de bout en bout
  • Authentification sans réécrire les flux
  • Base pour ajouter plus tard recherche, mode hors‑ligne et collaboration temps réel

Choix technologiques (et pourquoi)

Préoccupation Choix Raison
Runtime SPA & UI Blazor WebAssembly (.NET 9) C# partout, composants réutilisables
Composants UI MudBlazor Material Design, dialogues, tableaux, theming
Backend Supabase PostgreSQL + Auth + Realtime + REST + RLS
Modélisation PostgREST + attributs C# Mappage direct, peu de couches au départ
Validation DataAnnotations Intégré, simple, testable
Tests xUnit Standard .NET, exécution parallèle
Déploiement (cible) Hébergement statique/CDN Coût réduit + distribution mondiale

Architecture haut niveau

( U + t B M i l W u l a A d i z S B s o M l a r z t r e u r ) C l i e n t S u p a A P b u o a t s s h t e C g a r n e a S u Q x L R e a l t i m e

Le navigateur télécharge l’application Blazor une fois; ensuite les appels vont directement aux endpoints REST Supabase (SDK officiel).

Extrait de code clé

Configuration de Supabase au démarrage :

var options = new SupabaseOptions
{
    AutoRefreshToken = true,
    AutoConnectRealtime = true
};

builder.Services.AddSingleton(sp =>
    new Client(
        builder.Configuration["supabase:Url"] ?? string.Empty,
        builder.Configuration["supabase:Key"] ?? string.Empty,
        options
    )
);

builder.Services.AddScoped<ISupabaseAuthWrapper, SupabaseAuthWrapper>();
builder.Services.AddScoped<AuthService>();

Isolation de l’authentification :

public class SupabaseAuthWrapper : ISupabaseAuthWrapper
{
    private readonly Supabase.Client _client;

    public async Task<Session?> SignIn(string email, string password) =>
        await _client.Auth.SignIn(email, password);

    public async Task SignOut() => await _client.Auth.SignOut();

    public User? CurrentUser => _client.Auth.CurrentUser;
}

Modèle relié directement à la table :

[Table("recettes")]
public class Recipe : BaseModel
{
    [PrimaryKey("id")] public int Id { get; set; }
    [Column("name"), Required] public string Name { get; set; } = string.Empty;
    [Column("rating"), Range(1,5)] public int Rating { get; set; }
    [Column("notes")] public string? Notes { get; set; }
    [Column("book_id")] public int? BookId { get; set; }
    [Reference(typeof(Book), joinType: ReferenceAttribute.JoinType.Left, true)]
    public Book? Book { get; set; }
}

Réalisé vs. prévu

Domaine Statut
Auth (email/mot de passe) Implémenté
Modèles (Recette / Livre / Auteur / Jonction) Implémentés
UI CRUD de base Implémentée (dialogues & pages)
Validation note (1–5) Implémentée + tests
Repository / Unit of Work Documenté (pas encore câblé)
Couche de cache Prévu (pattern rédigé)
Mises à jour temps réel Activées côté config; amélioration ciblée
Recherche plein texte & index Prévu (exemples SQL)
Pipeline CI/CD Documenté; workflow à ajouter

Leçons à ce stade

  1. Supabase + Blazor réduit fortement le temps jusqu’à la première fonctionnalité.
  2. Garder les modèles proches du schéma est acceptable tôt; on abstraira plus tard.
  3. DataAnnotations restent suffisants pour les contraintes initiales.
  4. MudBlazor accélère l’UI mais il faut centraliser les décisions de thème tôt.

Prochaines étapes

  • Introduire un RecipeService + décorateur de cache
  • RLS pour contraindre la propriété par utilisateur
  • Tests d’intégration sur instance Supabase de staging
  • Écoute Realtime pour refléter les modifications concurrentes

Source

GitHub : https://github.com/mongeon/RecettesIndex



Suggestions de lecture :