@dariomvg/create
supabaseuser-managementperfilnextjsintegracion

Supabase User Management para Next.js App Router

Módulo de gestión de usuarios de autoservicio: obtener/actualizar el perfil, cambiar el email, cambiar la contraseña, avatar, nombre, metadata, preferencias del usuario y eliminar la propia cuenta. Está separado del módulo de auth: es autocontenido y vive en su propia carpeta.

Dependencias

  • @supabase/ssr
  • @supabase/supabase-js

Dónde vive cada cosa

ArchivoPropósito
types.tsTipos compartidos (UserProfile, UserManagementResult<T>, UserManagementError, etc.)
service.tsLógica interna: cliente de Supabase para el servidor + todas las operaciones de gestión de usuarios. No se importa fuera de este módulo.
actions.ts"use server" — la API pública del lado del servidor. Importá desde acá en Server Components / formularios.
client.tsCliente de Supabase para el navegador + funciones listas para usar en Client Components.
env.example.mdVariables de entorno necesarias.

Este módulo no incluye proxy.ts ni route.ts: la protección de rutas ya la resuelve el proxy.ts del módulo de auth, y la confirmación del cambio de email reutiliza tal cual el app/auth/callback/route.ts del módulo de auth.

Uso

Leer el perfil actual (Server Component)

import { getCurrentUserProfile } from '@/lib/user-management/supabase/actions';

export default async function AccountPage() {
  const { data: profile } = await getCurrentUserProfile();
  return <p>{profile?.name ?? profile?.email}</p>;
}

Actualizar nombre / metadata / preferencias (Client Component)

'use client';
import { updateNameClient, updatePreferencesClient } from '@/lib/user-management/supabase/client';

await updateNameClient('Dari');
await updatePreferencesClient({ theme: 'dark' });

Cambiar la contraseña (requiere la contraseña actual)

import { changePasswordAction } from '@/lib/user-management/supabase/actions';

const { error } = await changePasswordAction({ currentPassword, newPassword });

Cambiar el email

import { changeEmailAction } from '@/lib/user-management/supabase/actions';

await changeEmailAction({ newEmail }); // confirmation email → app/auth/callback/route.ts

Subir un avatar (Server Action desde un formulario)

import { uploadAvatarAction } from '@/lib/user-management/supabase/actions';

<form action={uploadAvatarAction}>
  <input type="file" name="avatar" accept="image/*" />
  <button type="submit">Upload</button>
</form>

Eliminar la propia cuenta

import { deleteOwnAccountAction } from '@/lib/user-management/supabase/actions';

await deleteOwnAccountAction(); // signs the user out afterward

Configuración

Pasos que el CLI no puede automatizar: hacelos manualmente en el dashboard de Supabase:

  1. Bucket de Storage: creá un bucket llamado avatars (Storage → New bucket). Hacelo público si querés que getPublicUrl sirva las imágenes directamente; si lo dejás privado, reemplazá getPublicUrl por createSignedUrl en service.ts/client.ts.
  2. Políticas RLS de Storage en avatars: restringí insert/update/delete a auth.uid()::text = (storage.foldername(name))[1] para que cada usuario solo pueda escribir dentro de su propia carpeta (el módulo ya sube a <user_id>/<filename>).
  3. Service role key: copiá SUPABASE_SERVICE_ROLE_KEY desde Project Settings → API a tu .env.local. Mantenela fuera del control de versiones y nunca la expongas al cliente.
  4. Dependencia del módulo de auth: este módulo asume que app/auth/callback/route.ts (del boilerplate de auth) ya existe en el proyecto: las confirmaciones de cambio de email redirigen ahí.

Alcance

Solo autoservicio. No hay listUsers, searchUsers ni eliminación de cuentas de otros usuarios: son operaciones de nivel administrador que necesitarían su propia capa de autorización, algo que queda fuera del alcance de este módulo.