🔄 Migración de Laravel a Supabase - Resumen
📊 Cambios Principales
❌ Eliminado del Stack
| Componente | Razón |
|---|---|
| Laravel | Reemplazado por Supabase (BaaS) |
| Railway Backend | Ya no se necesita servidor PHP |
| Laravel Sanctum | Supabase Auth lo reemplaza |
| Filament Admin | Dashboard propio en Next.js |
| personal_access_tokens | JWT de Supabase |
✅ Agregado al Stack
| Componente | Beneficio |
|---|---|
| Supabase | BaaS todo-en-uno |
| Supabase Auth | Auth nativo con @uc.cl |
| Row Level Security | Seguridad a nivel BD |
| Edge Functions | Serverless para Gemini AI |
| Supabase Storage | Fotos de perfil |
| Realtime | Notificaciones 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.dataAhora (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)
| Tarea | Laravel | Supabase | Diferencia |
|---|---|---|---|
| Setup backend | 30 min | 5 min | -25 min |
| Auth | 20 min | 5 min | -15 min |
| CRUD endpoints | 60 min | 0 min | -60 min |
| Admin panel | 45 min | 30 min | -15 min |
| Deploy backend | 15 min | 0 min | -15 min |
| TOTAL | 170 min | 40 min | -130 min |
Ganancia: ~2 horas para enfocarse en features y UX
💰 Costos
Antes (Laravel)
| Servicio | Costo Hackathon | Costo Producción |
|---|---|---|
| Railway (backend) | $5 gratis | ~$10/mes |
| Railway (PostgreSQL) | Incluido | Incluido |
| Vercel (frontend) | Gratis | Gratis |
| TOTAL | $0* | $10/mes |
*$5 crédito inicial
Ahora (Supabase)
| Servicio | Costo Hackathon | Costo Producción |
|---|---|---|
| Supabase (todo) | Gratis | Gratis hasta escala |
| Vercel (frontend) | Gratis | Gratis |
| TOTAL | $0 | $0-25/mes |
🎯 Ventajas de la Migración
✅ Técnicas
- Menos código: Sin backend REST API
- Type-safe: Cliente Supabase tipado
- Realtime gratis: Sin configurar Pusher
- RLS nativo: Seguridad a nivel BD
- Edge Functions: Deploy serverless
- Un solo lenguaje: TypeScript end-to-end
✅ Desarrollo
- Setup 5x más rápido: 5 min vs 30 min
- Menos bugs: Menos código = menos errores
- DX mejor: Supabase Studio visual
- Hot reload: Todo en desarrollo local
- Testing más fácil: Supabase CLI
✅ Deploy
- Un servicio menos: Solo Vercel
- Más barato: Free tier más generoso
- Auto-scaling: Supabase maneja carga
- Backups automáticos: Incluidos en Supabase
⚠️ Desventajas
❌ Lo que se pierde
- Filament admin: Panel muy robusto
- Solución: Crear dashboard custom con shadcn/ui
- Control total backend: Menos customizable
- Solución: Edge Functions para lógica custom
- 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:
- Exportar datos de Supabase
- Crear backend Laravel
- Importar datos
- Cambiar frontend a usar API REST
Pero probablemente no querrás 😉
🚀 Próximos Pasos
- ✅ Leer documentación Supabase Auth
- ✅ Practicar queries con Supabase client
- ✅ Probar Edge Functions localmente
- ✅ Familiarizarse con RLS
- 🔜 Empezar hackathon con confianza
¡Supabase nos va a ayudar a ganar! 🎉