Casos de Uso

Plataforma / AI Ops

Cómo construí esta plataforma — con AI, desde cero, sin un solo desarrollador

Lo que estás leyendo es el resultado

Esta plataforma — la que estás usando ahora mismo — no fue construida por un equipo de desarrollo. No hubo un CTO, no hubo un freelancer en Upwork, no hubo un sprint de dos semanas.

La construyó un agente de AI llamado Cori, operado por mí a través de WhatsApp, en una sola noche.

Este es el log completo. Cada paso, cada decisión, cada error, cada comando que se ejecutó. Sin editar.


El punto de partida

Herramienta: OpenClaw — un sistema operativo de AI personal que corre en mi Mac mini en casa, disponible 24/7, que recibe instrucciones por WhatsApp y ejecuta tareas reales en mi computadora.

Punto de partida: Un dominio comprado (mo-insider.com), una idea de lo que quería construir, y un agente con acceso a terminal.

Lo que quería: Una plataforma de membresía con:

  • Registro con aprobación manual (yo apruebo quién entra)
  • Cursos con contenido estructurado
  • Comunidad (foro interno)
  • Newsletter desde el propio dominio
  • Panel de admin para gestionar miembros

Tiempo total: Una noche (aproximadamente 6 horas de trabajo real del agente)


Fase 1 — Arquitectura y stack

Lo primero fue decidir el stack. Le pregunté a Cori qué tenía sentido para lo que quería construir. La respuesta:

Stack recomendado:
- Next.js 14 (App Router) — frontend + API routes
- Supabase — base de datos PostgreSQL + autenticación
- Resend — emails transaccionales
- Vercel — deployment y hosting
- TypeScript — para no morir en errores de runtime

Razones concretas: Supabase tiene Row Level Security (RLS) nativo — esencial para que los miembros solo vean lo que deben ver. Vercel se integra con Supabase automáticamente. Resend es el servicio de email más limpio del mercado para developers. Next.js 14 permite tener backend y frontend en el mismo proyecto.

Costo mensual estimado del stack: $0–20 USD/mes en el nivel gratuito de todas las plataformas.


Fase 2 — Build: 26 archivos, cero errores de compilación

Cori construyó el proyecto completo en una sola pasada. 26 archivos, todos funcionales:

Autenticación y acceso:

  • middleware.ts — protege /cursos, /comunidad, /admin. Si no estás autenticado o aprobado, te redirige al login
  • app/login/page.tsx — página de login conectada a Supabase Auth
  • lib/supabase.ts — cliente de Supabase con inicialización lazy (importante: esto se corrigió después, más abajo)

Registro y aprobación:

  • components/JoinModal.tsx — formulario de 7 campos: nombre, apellido, empresa, sector, uso actual de AI, objetivos, cómo llegaste
  • app/api/notify-admin/route.ts — cuando alguien aplica, me llega una notificación
  • app/api/approve-member/route.ts — apruebo desde el panel, el sistema manda email de bienvenida
  • app/api/send-newsletter/route.ts — newsletter con personalización {{nombre}}

Panel de admin (/admin):

  • Tab 1: solicitudes pendientes de aprobación
  • Tab 2: miembros activos (con opción de suspender)
  • Tab 3: compositor de newsletter

Comunidad (/comunidad):

  • Posts y respuestas conectados a Supabase en tiempo real
  • Políticas RLS: solo miembros aprobados pueden postear

Cursos (/cursos):

  • Estructura modular, protegida por auth
  • Curso 1 y Curso 2 con sus respectivos módulos

Total: 140 archivos en el commit final (incluyendo dependencias configuradas, assets, schema SQL, vercel.json)


Fase 3 — Base de datos: el schema SQL

Cori escribió el schema completo para Supabase. Esto fue lo que se ejecutó en el SQL Editor de Supabase:

-- Tabla principal de miembros
CREATE TABLE members (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  email TEXT UNIQUE NOT NULL,
  first_name TEXT NOT NULL,
  last_name TEXT NOT NULL,
  company TEXT NOT NULL,
  industry TEXT NOT NULL,
  industry_other TEXT,
  ai_usage TEXT NOT NULL,
  goals TEXT NOT NULL,
  how_found TEXT NOT NULL,
  referral_name TEXT,
  status TEXT DEFAULT 'pending' 
    CHECK (status IN ('pending', 'approved', 'rejected', 'suspended')),
  created_at TIMESTAMPTZ DEFAULT NOW(),
  approved_at TIMESTAMPTZ,
  approved_by TEXT
);

-- Tabla de posts de la comunidad
CREATE TABLE posts (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  author_id UUID REFERENCES members(id) ON DELETE CASCADE,
  title TEXT NOT NULL,
  body TEXT NOT NULL,
  category TEXT NOT NULL,
  pinned BOOLEAN DEFAULT FALSE,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Tabla de respuestas
CREATE TABLE replies (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  post_id UUID REFERENCES posts(id) ON DELETE CASCADE,
  author_id UUID REFERENCES members(id) ON DELETE CASCADE,
  body TEXT NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Vista para newsletter (solo miembros aprobados)
CREATE VIEW newsletter_list AS
  SELECT id, email, first_name FROM members
  WHERE status = 'approved';

Row Level Security — las políticas que controlan quién ve qué:

-- Habilitar RLS en todas las tablas
ALTER TABLE members ENABLE ROW LEVEL SECURITY;
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
ALTER TABLE replies ENABLE ROW LEVEL SECURITY;

-- Cualquiera puede registrarse (insertar su propio registro)
CREATE POLICY "allow_registration" ON members
  FOR INSERT WITH CHECK (auth.uid() = id);

-- Un miembro solo puede ver su propio perfil
CREATE POLICY "members_read_own" ON members
  FOR SELECT USING (auth.uid() = id);

-- Solo miembros aprobados pueden ver y crear posts
CREATE POLICY "approved_members_posts" ON posts
  FOR ALL USING (
    EXISTS (
      SELECT 1 FROM members 
      WHERE id = auth.uid() AND status = 'approved'
    )
  );

Cómo se ejecutó: Supabase tiene un SQL Editor en el dashboard. Cori abrió el browser, navegó a supabase.com, abrió el SQL Editor del proyecto, pegó el schema completo, y presionó Run. Resultado: "No rows returned" — lo que significa éxito (el schema no devuelve datos, solo crea estructura).


Fase 4 — Deployment en Vercel

Problema 1: sin repositorio GitHub

La cuenta cori@gruponc44.com no tiene GitHub. La solución: Vercel CLI, que permite hacer deploy directo desde terminal sin repositorio.

# Desde el directorio del proyecto
cd /Users/ceo-nc44/the-mo-app

# Deploy a producción
vercel --prod --token [TOKEN]

El token se genera en vercel.com/account/tokens. Cori abrió el browser, navegó al dashboard de Vercel, generó el token, y lo usó en el comando.

Primer deploy: falló. Error: RESEND_API_KEY is not defined

El cliente de Resend se inicializaba al cargar el módulo (antes de que las variables de entorno estuvieran disponibles). Fix: inicialización lazy en las tres rutas afectadas.

// ❌ Antes — se inicializa al importar el módulo
const resend = new Resend(process.env.RESEND_API_KEY);

// ✅ Después — se inicializa solo cuando se llama la función
function getResend() {
  return new Resend(process.env.RESEND_API_KEY);
}

Segundo deploy: compiló. Pero error en browser: supabaseKey is required

El bundle de Next.js había compilado el cliente de Supabase con la variable NEXT_PUBLIC_SUPABASE_ANON_KEY vacía (se había cargado mal en Vercel). El hash del chunk JS estaba cacheado. Fix: mismo patrón de lazy initialization para el cliente de Supabase, forzando regeneración del bundle.

// lib/supabase.ts — versión final
import { createClient } from "@supabase/supabase-js";

let _client: ReturnType<typeof createClient> | null = null;

export function getSupabaseClient() {
  if (!_client) {
    _client = createClient(
      process.env.NEXT_PUBLIC_SUPABASE_URL!,
      process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
    );
  }
  return _client;
}

Tercer deploy: éxito. 26 páginas generadas, cero errores.

🟢 https://the-mo-app.vercel.app — live.


Fase 5 — Dominio propio y DNS

Dominio: mo-insider.com, comprado en Namecheap.

Paso 1 — Agregar dominio a Vercel:

En el dashboard de Vercel → proyecto → Settings → Domains → agregar mo-insider.com.

Vercel provee los registros DNS necesarios:

  • A Record: @76.76.21.21
  • CNAME Record: wwwcname.vercel-dns.com

Paso 2 — Configurar en Namecheap Advanced DNS:

Nota real del proceso: el CNAME tenía un typo — decía came.vercel-dns.com en lugar de cname.vercel-dns.com. Se detectó revisando el screenshot que me mandé a mí mismo y se corrigió antes de guardar.

Resultado: SSL auto-provisionado por Vercel. mo-insider.com activo en ~10 minutos.


Fase 6 — Email transaccional con Resend

Resend es el servicio de email para developers. Permite enviar emails transaccionales (bienvenidas, aprobaciones, newsletters) desde tu propio dominio con excelente deliverability.

Pasos ejecutados:

1. Crear cuenta en resend.com con cori@gruponc44.com

2. Confirmar cuenta — llegó un email de confirmación. Cori abrió el link desde el inbox de Gmail usando gog (Google Workspace CLI):

gog gmail search "from:resend" --account cori@gruponc44.com
# → encontró el email con el link de confirmación
# → Cori abrió el link en el browser y presionó "Confirm account"

3. API Key generada: re_6MJBqoap_... — agregada a Vercel como variable de entorno:

vercel env add RESEND_API_KEY production --token [TOKEN]
# → prompts por el valor → se ingresa la key
# → "Added Environment Variable RESEND_API_KEY to Project the-mo-app"

4. Verificar dominio mo-insider.com en Resend:

Resend requiere registros DNS para confirmar que eres el dueño del dominio y para mejorar la deliverability.

Registros DNS agregados en Namecheap:

Tipo Host Valor Para qué sirve
TXT resend._domainkey p=MIGfMA0G... DKIM — firma digital de los emails
TXT send v=spf1 include:amazonses.com ~all SPF — autoriza a Amazon SES a enviar en nombre del dominio

DKIM (DomainKeys Identified Mail): Firma criptográfica que prueba que el email no fue alterado en tránsito. Sin esto, los emails pueden terminar en spam.

SPF (Sender Policy Framework): Lista de servidores autorizados a enviar emails desde tu dominio. Resend usa la infraestructura de Amazon SES, por eso se incluye amazonses.com.

Estado: DNS propagando (Namecheap puede tardar hasta 2 horas). Una vez verificado, los emails salen desde hola@mo-insider.com.


Fase 7 — Usuario de prueba (cómo se creó mi acceso)

No quería pasar por el flujo de aprobación para testear la plataforma. Cori creó mi usuario directamente via la API de Supabase:

Paso 1 — Crear usuario en Supabase Auth:

curl -X POST "https://[proyecto].supabase.co/auth/v1/admin/users" \
  -H "apikey: [SERVICE_ROLE_KEY]" \
  -H "Authorization: Bearer [SERVICE_ROLE_KEY]" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "michel.olmi@gmail.com",
    "password": "...",
    "email_confirm": true
  }'
# → "id": "2b39bd21-...", "email": "michel.olmi@gmail.com"

Paso 2 — Insertar en tabla members como approved:

curl -X POST "https://[proyecto].supabase.co/rest/v1/members" \
  -H "apikey: [SERVICE_ROLE_KEY]" \
  -H "Authorization: Bearer [SERVICE_ROLE_KEY]" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "2b39bd21-...",
    "email": "michel.olmi@gmail.com",
    "first_name": "Michel",
    "last_name": "Olmi",
    "company": "RiTMO",
    "industry": "Retail",
    "ai_usage": "A diario personal",
    "goals": "Acceso completo",
    "how_found": "Referido",
    "status": "approved"
  }'

Resultado: acceso completo a cursos, comunidad y admin.


Lo que esto demuestra

Tiempo total: ~6 horas (una noche)

Costo de desarrollo: $0 (el agente ya estaba operando)

Costo mensual del stack:

Servicio Plan Costo
Vercel Hobby (gratuito) $0
Supabase Free tier $0
Resend Free (3,000 emails/mes) $0
Namecheap (dominio) Anual ~$15/año
OpenClaw Suscripción mensual $30/mes

Total operativo: ~$30/mes para una plataforma completa con auth, base de datos, emails, comunidad, cursos y panel de admin.


La pregunta que importa

¿Podría haber contratado a un desarrollador para hacer esto?

Sí. Costo estimado: $3,000–8,000 USD para un proyecto de esta envergadura, más 2–4 semanas de tiempo.

¿Vale la pena aprender a operar un agente de AI para este tipo de trabajo?

Depende de cuántas veces necesites construir algo. Si es una vez, quizás no. Si construyes sistemas continuamente — plataformas, automatizaciones, herramientas internas — la respuesta es sí, con mucho margen.

No se trata de reemplazar developers. Se trata de poder ejecutar sin depender de ellos para proyectos donde la velocidad y el costo importan.


El stack completo para replicarlo

Si quisieras construir algo similar:

  1. OpenClaw — instalación en Mac o VPS, conexión por WhatsApp
  2. Node.js + Next.js 14npx create-next-app@latest --typescript
  3. Supabase — crear proyecto en supabase.com, copiar URL y keys
  4. Vercel — conectar proyecto o usar CLI (npm i -g vercel)
  5. Resend — crear cuenta, verificar dominio, obtener API key
  6. Namecheap (o cualquier registrar) — configurar DNS records

El agente hace el resto. Lo que necesitas es saber qué quieres construir — no cómo construirlo.