🔄 Migración de Laravel a Supabase - Resumen

📊 Cambios Principales

❌ Eliminado del Stack

ComponenteRazón
LaravelReemplazado por Supabase (BaaS)
Railway BackendYa no se necesita servidor PHP
Laravel SanctumSupabase Auth lo reemplaza
Filament AdminDashboard propio en Next.js
personal_access_tokensJWT de Supabase

✅ Agregado al Stack

ComponenteBeneficio
SupabaseBaaS todo-en-uno
Supabase AuthAuth nativo con @uc.cl
Row Level SecuritySeguridad a nivel BD
Edge FunctionsServerless para Gemini AI
Supabase StorageFotos de perfil
RealtimeNotificaciones live

🗄️ Cambios en Base de Datos

Tipos de Datos

Antes (Laravel):

id BIGINT GENERATED BY DEFAULT AS IDENTITY
created_at timestamp DEFAULT (now())

Ahora (Supabase):

id UUID DEFAULT gen_random_uuid()
created_at TIMESTAMPTZ DEFAULT NOW()

Autenticación

Antes:

CREATE TABLE users (
  id bigint PRIMARY KEY,
  email varchar(255),
  password varchar(255),
  email_verified boolean
);

Ahora:

-- Supabase Auth maneja auth.users
CREATE TABLE profiles (
  id UUID REFERENCES auth.users(id),
  email TEXT CHECK (email LIKE '%@uc.cl'),
  -- password manejado por Supabase
);

Seguridad

Antes (Laravel):

  • Middleware en rutas
  • Policies en Eloquent
  • Gates para autorización

Ahora (Supabase):

  • Row Level Security (RLS)
  • Policies SQL nativas
  • auth.uid() en queries
-- Ejemplo RLS
CREATE POLICY "Solo dueño edita perfil"
  ON profiles FOR UPDATE
  USING (auth.uid() = id);

🔐 Autenticación

Flujo Antes (Laravel Sanctum)

// 1. Login
POST /api/login
{ email, password }
→ { token: "xyz..." }
 
// 2. Requests
GET /api/tutors
Headers: { Authorization: "Bearer xyz..." }

Flujo Ahora (Supabase Auth)

// 1. Login
const { data, error } = await supabase.auth.signInWithPassword({
  email: 'user@uc.cl',
  password: 'pass'
})
 
// 2. Queries (automático)
const { data } = await supabase
  .from('tutores')
  .select('*')
// Session manejada por client

📡 Queries

Antes (Laravel API)

Backend:

// app/Http/Controllers/TutorController.php
public function index(Request $request) {
    $tutors = Tutor::with(['user', 'ramos'])
        ->where('campus', $request->campus)
        ->get();
    return response()->json($tutors);
}

Frontend:

const response = await axios.get('/api/tutors?campus=San+Joaquín')
const tutors = response.data

Ahora (Supabase Client)

Solo Frontend:

const { data: tutors } = await supabase
  .from('tutores')
  .select(`
    *,
    profiles!inner(*),
    tutor_ramo(*, ramos(*))
  `)
  .eq('campus', 'San Joaquín')

🎨 Admin Panel

Antes (Filament)

// app/Filament/Resources/TutorResource.php
class TutorResource extends Resource {
    public static function form(Form $form) {
        return $form->schema([
            TextInput::make('bio'),
            Select::make('campus'),
            // ...
        ]);
    }
}

Ahora (Next.js + shadcn)

// app/tutor/dashboard/page.tsx
export default function TutorDashboard() {
  return (
    <div>
      <h1>Dashboard</h1>
      <StatsCards />
      <UpcomingSessions />
      <PendingRequests />
    </div>
  )
}

🤖 Gemini AI

Antes (Laravel Controller)

// app/Http/Controllers/GeminiController.php
use Google\GenerativeAI\Client;
 
public function match(Request $request) {
    $client = new Client(env('GEMINI_API_KEY'));
    $response = $client->generateContent($prompt);
    return response()->json($response);
}

Ahora (Edge Function)

// supabase/functions/gemini-match/index.ts
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'
import { GoogleGenerativeAI } from '@google/generative-ai'
 
serve(async (req) => {
  const genAI = new GoogleGenerativeAI(Deno.env.get('GEMINI_API_KEY'))
  const result = await model.generateContent(prompt)
  return new Response(JSON.stringify(result))
})

📦 Dependencias

Antes (Laravel)

{
  "require": {
    "php": "^8.2",
    "laravel/framework": "^11.0",
    "laravel/sanctum": "^4.0",
    "filament/filament": "^3.0"
  }
}
{
  "dependencies": {
    "next": "^14.0.0",
    "axios": "^1.6.0",
    "react": "^18.2.0"
  }
}

Ahora (Solo Next.js + Supabase)

{
  "dependencies": {
    "next": "^14.0.0",
    "@supabase/supabase-js": "^2.39.0",
    "@supabase/auth-helpers-nextjs": "^0.8.0",
    "react": "^18.2.0"
  }
}

⚡ Velocidad de Desarrollo

Timeline Comparativa (9 horas)

TareaLaravelSupabaseDiferencia
Setup backend30 min5 min-25 min
Auth20 min5 min-15 min
CRUD endpoints60 min0 min-60 min
Admin panel45 min30 min-15 min
Deploy backend15 min0 min-15 min
TOTAL170 min40 min-130 min

Ganancia: ~2 horas para enfocarse en features y UX


💰 Costos

Antes (Laravel)

ServicioCosto HackathonCosto Producción
Railway (backend)$5 gratis~$10/mes
Railway (PostgreSQL)IncluidoIncluido
Vercel (frontend)GratisGratis
TOTAL$0*$10/mes

*$5 crédito inicial

Ahora (Supabase)

ServicioCosto HackathonCosto Producción
Supabase (todo)GratisGratis hasta escala
Vercel (frontend)GratisGratis
TOTAL$0$0-25/mes

🎯 Ventajas de la Migración

✅ Técnicas

  1. Menos código: Sin backend REST API
  2. Type-safe: Cliente Supabase tipado
  3. Realtime gratis: Sin configurar Pusher
  4. RLS nativo: Seguridad a nivel BD
  5. Edge Functions: Deploy serverless
  6. Un solo lenguaje: TypeScript end-to-end

✅ Desarrollo

  1. Setup 5x más rápido: 5 min vs 30 min
  2. Menos bugs: Menos código = menos errores
  3. DX mejor: Supabase Studio visual
  4. Hot reload: Todo en desarrollo local
  5. Testing más fácil: Supabase CLI

✅ Deploy

  1. Un servicio menos: Solo Vercel
  2. Más barato: Free tier más generoso
  3. Auto-scaling: Supabase maneja carga
  4. Backups automáticos: Incluidos en Supabase

⚠️ Desventajas

❌ Lo que se pierde

  1. Filament admin: Panel muy robusto
    • Solución: Crear dashboard custom con shadcn/ui
  2. Control total backend: Menos customizable
    • Solución: Edge Functions para lógica custom
  3. Eloquent ORM: Muy cómodo
    • Solución: Supabase client es bastante ergonómico

📋 Checklist de Migración

✅ Completado

  • Schema SQL adaptado a Supabase
  • UUIDs en lugar de BIGINT
  • RLS policies creadas
  • Auth integrado con auth.users
  • Triggers para updated_at
  • Funciones SQL para cálculos
  • Vistas para queries complejas
  • Documentación actualizada
  • Plan de desarrollo actualizado
  • Resumen ejecutivo actualizado

🔄 Pendiente (durante hackathon)

  • Seeders adaptados a TypeScript
  • Queries frontend escritas
  • Edge Functions para Gemini
  • Dashboard de tutor en Next.js
  • Testing de RLS policies

🎓 Recursos de Aprendizaje

Supabase

Next.js + Supabase


💬 Preguntas Frecuentes

¿Por qué Supabase sobre Laravel?

Para este hackathon de 9 horas, Supabase nos permite:

  • Setup 5x más rápido
  • No mantener backend separado
  • TypeScript end-to-end
  • Realtime sin configuración
  • Free tier más generoso

¿Qué pasa con el admin panel de Filament?

Lo reemplazamos con un dashboard custom en Next.js usando shadcn/ui. Toma ~30 min crear uno básico vs 45 min configurar Filament + backend.

¿Es Supabase production-ready?

Sí, usado por miles de apps en producción. Tiene:

  • 99.9% uptime SLA
  • Backups automáticos
  • Point-in-time recovery
  • Team de soporte

¿Puedo migrar de vuelta a Laravel después?

Sí, el schema SQL es estándar PostgreSQL. Podrías:

  1. Exportar datos de Supabase
  2. Crear backend Laravel
  3. Importar datos
  4. Cambiar frontend a usar API REST

Pero probablemente no querrás 😉


🚀 Próximos Pasos

  1. ✅ Leer documentación Supabase Auth
  2. ✅ Practicar queries con Supabase client
  3. ✅ Probar Edge Functions localmente
  4. ✅ Familiarizarse con RLS
  5. 🔜 Empezar hackathon con confianza

¡Supabase nos va a ayudar a ganar! 🎉