ScaleRocket/Web

Panneau d'administration

Tableau de bord d'administration pour la gestion des utilisateurs, le suivi des abonnements, l'édition de blog et les statistiques de la plateforme.

Vue d'ensemble

ScaleRocket inclut un panneau d'administration dans apps/ops/. Il fournit un tableau de bord avec les statistiques de la plateforme, la gestion des utilisateurs, le suivi des abonnements et un éditeur de blog. Seuls les utilisateurs autorisés peuvent y accéder.

Architecture

apps/ops/ (Vite + React)
  ├── src/pages/
  │   ├── dashboard.tsx       # Stats overview
  │   ├── users.tsx           # User management
  │   ├── subscriptions.tsx   # Subscription management
  │   └── blog/               # Blog editor
  ├── src/components/
  └── src/lib/
      └── supabase.ts         # Admin Supabase client

Le panneau d'administration utilise la clé service role de Supabase pour contourner le RLS et accéder à toutes les données. Il fonctionne comme une application Vite séparée déployée sur son propre domaine.

Sécurité

Liste blanche des administrateurs

L'accès est restreint à une liste d'adresses email autorisées :

// apps/ops/src/lib/auth.ts
const ADMIN_EMAILS = [
  "admin@yourdomain.com",
  // Add more admin emails here
];

export function isAdmin(email: string): boolean {
  return ADMIN_EMAILS.includes(email);
}

Protection des routes

// apps/ops/src/components/admin-guard.tsx
export function AdminGuard({ children }: { children: React.ReactNode }) {
  const { user, loading } = useAuth();

  if (loading) return <LoadingSpinner />;
  if (!user || !isAdmin(user.email)) {
    return <Navigate to="/unauthorized" />;
  }

  return children;
}

Client service role

Le panneau d'administration utilise la clé service role pour un accès illimité à la base de données :

// apps/ops/src/lib/supabase.ts
import { createClient } from "@supabase/supabase-js";

export const supabaseAdmin = createClient(
  import.meta.env.VITE_SUPABASE_URL,
  import.meta.env.VITE_SUPABASE_SERVICE_ROLE_KEY
);

Important : La clé service role n'est utilisée que dans l'application d'administration. Ne l'exposez jamais dans apps/web ou apps/app.

Statistiques du tableau de bord

Le tableau de bord affiche les métriques clés :

// apps/ops/src/pages/dashboard.tsx
const stats = [
  {
    label: "Total Users",
    value: await supabaseAdmin.from("profiles").select("*", { count: "exact", head: true }),
  },
  {
    label: "Active Subscriptions",
    value: await supabaseAdmin
      .from("subscriptions")
      .select("*", { count: "exact", head: true })
      .eq("status", "active"),
  },
  {
    label: "MRR",
    value: calculateMRR(subscriptions),
  },
  {
    label: "Signups (30d)",
    value: await supabaseAdmin
      .from("profiles")
      .select("*", { count: "exact", head: true })
      .gte("created_at", thirtyDaysAgo),
  },
];

Gestion des utilisateurs

Consultez, recherchez et gérez tous les utilisateurs :

// Fetch users with their subscription status
const { data: users } = await supabaseAdmin
  .from("profiles")
  .select(`
    *,
    subscriptions (status, plan_id, current_period_end),
    credits (balance, monthly_allowance)
  `)
  .order("created_at", { ascending: false });

Actions d'administration disponibles :

  • Voir les détails de l'utilisateur : Profil, abonnement, solde de crédits
  • Mettre à jour l'abonnement : Changer de plan, prolonger la période
  • Accorder des crédits : Ajouter manuellement des crédits à un utilisateur
  • Supprimer l'utilisateur : Supprimer l'utilisateur et toutes les données associées

Gestion des abonnements

Consultez et filtrez tous les abonnements :

const { data: subscriptions } = await supabaseAdmin
  .from("subscriptions")
  .select(`
    *,
    profiles (email, full_name)
  `)
  .order("created_at", { ascending: false });

Filtrez par statut (active, canceled, past_due) ou par plan.

Éditeur de blog

Le panneau d'administration inclut un éditeur de blog basique pour publier du contenu sur le site marketing :

apps/ops/src/pages/blog/
  ├── index.tsx          # Blog post list
  ├── editor.tsx         # Create/edit posts
  └── preview.tsx        # Preview before publish

Les articles de blog sont stockés dans une table posts :

CREATE TABLE posts (
  id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
  title text NOT NULL,
  slug text UNIQUE NOT NULL,
  content text,
  excerpt text,
  cover_image text,
  published boolean DEFAULT false,
  author_id uuid REFERENCES profiles(id),
  published_at timestamptz,
  created_at timestamptz DEFAULT now(),
  updated_at timestamptz DEFAULT now()
);

Le site marketing (apps/web) récupère les articles publiés et les affiche.

Lancer le panneau d'administration

# From the monorepo root
pnpm --filter ops dev

# Or using Turborepo
pnpm turbo dev --filter=ops

Le panneau d'administration fonctionne sur http://localhost:5174 par défaut.

Fini ? Marquez cette page comme terminée.

On this page