Para tener una web propia —la de tu farmacia, una herramienta interna, un panel con tus ventas— hacen falta cuatro piezas, y sólo una es de IA. Merece la pena entender qué hace cada una antes de tocar ninguna, porque la mayoría de los líos vienen de pedirle a una lo que le toca a otra.
| Pieza | Qué hace | Si falta… |
|---|---|---|
| GitHub | Guarda el código y todo su historial. Cada cambio queda con su fecha y se puede deshacer. | Un cambio que rompe algo no se puede volver atrás. Es la pieza que más se salta y la que más cara sale. |
| Vercel | Coge lo que hay en GitHub y lo sirve en internet, con su dominio y su certificado. | Tienes el código y no lo ve nadie. |
| Supabase | La base de datos y las cuentas de usuario. Lo que hay que guardar y quién puede leerlo. | La web funciona pero no recuerda nada: ni un pedido, ni un cliente, ni una cuenta. |
| Claude Code o Codex |
Escribe el código, dentro de tu propio proyecto. | Lo escribes tú, o lo encargas. |
Por qué en este orden
GitHub primero siempre, aunque el proyecto sean dos ficheros. Con un agente escribiendo, la pregunta no es si va a romper algo: es si el día que lo rompa vas a poder volver atrás. Sin historial, la respuesta es no — y no hay aviso, porque un fichero sobrescrito se ve exactamente igual que uno que nunca existió.
Después Vercel, conectado a GitHub. A partir de ahí cada cambio que subas se publica solo, en un minuto. Eso es justo lo bueno y justo la trampa: no hay un botón de «ahora sí, publica». Lo que pusiste está puesto.
Supabase entra cuando hay algo que recordar. Y Claude Code o Codex, en cuanto existe el repositorio — antes no, porque su contexto es el proyecto.
Qué cuesta
Los cuatro tienen plan gratuito, y para una web de farmacia con tráfico normal el gratuito llega. Las cifras concretas no las pongo aquí a propósito: cambian cada pocos meses y una lección con números caducados es peor que una sin ellos. Lo que no cambia es la forma:
- GitHub es gratis para lo que vas a hacer, incluso con el repositorio privado.
- Vercel cobra por tráfico y por funciones de servidor. Una web que sirve páginas no se acerca al límite; una que llama a una IA en cada visita, sí.
- Supabase cobra por espacio y por base de datos activa. Ojo con una cosa que no es precio: pausa los proyectos gratuitos inactivos.
- Claude Code / Codex es lo único con coste seguro, y es por uso.
El montaje, paso a paso
-
Crea el repositorio en GitHub
Privado. Y con esto dentro desde el primer commit: un
READMEque diga qué es esto —lo va a leer el agente— y un.gitignore.Lo que NUNCA entra en el repositorio: claves, tokens, contraseñas, ficheros
.env. Una clave subida a GitHub sigue en el historial aunque la borres en el commit siguiente: hay que rotarla, no borrarla. -
Conecta Vercel al repositorio
Importas el repositorio y ya está: cada push a la rama principal publica. Lo que de verdad importa aprender aquí son dos cosas.
Trabaja en ramas. Una rama por cambio, y Vercel te da una URL de prueba para ESA rama. Puedes verlo funcionando sin tocar lo que hay publicado.
Y las variables de entorno van en Vercel, no en el código. Es el sitio donde viven las claves. Ahí las lee tu servidor y no las ve el navegador.
-
Supabase: la base de datos y las cuentas
Dos cosas que se entienden mal y hay que entender bien, porque de ellas depende que los datos de tu farmacia estén cerrados o abiertos.
La clave «anon» es pública por diseño. Va en el navegador, se ve en el código fuente y no pasa nada — lo que protege cada fila no es la clave, es la RLS. Quien te diga que escondas la anon está resolviendo el problema equivocado.
Y la clave «service role» se salta la RLS entera. Esa NO baja al navegador jamás: vive en las variables de Vercel y sólo la usa tu servidor. Es el único error de esta lección que no se puede deshacer —quien la tenga, tiene todo— así que si alguna vez dudas de si se ha escapado, se rota y ya.RLS activada desde el minuto uno, tabla por tabla. Una tabla con RLS y sin políticas no deja entrar a nadie, que es un problema visible y se arregla en un minuto. Una tabla sin RLS la lee cualquiera con la clave anon, que es un problema invisible.
Y una trampa concreta: si activas RLS y sólo escribes política de
SELECT, los borrados fallan en silencio — la petición devuelve «sin error» y no borra nada. Hace falta una política por verbo. -
Claude Code o Codex, dentro del repositorio
No es un chat al que le pegas código: se abre en tu proyecto y lee los ficheros. Por eso el orden importa — con el repositorio ya montado, el agente ve cómo está hecho lo que hay y escribe en ese estilo.
Cómo se le dirige, qué se le pide y cómo se comprueba lo que devuelve es la lección siguiente.
Los cuatro errores que más caros salen
| Error | Qué pasa | Cómo se evita |
|---|---|---|
La clave service_role en el navegador |
Cualquiera lee y escribe toda tu base de datos | Sólo en variables de entorno de Vercel. Si dudas, rótala |
| Una tabla sin RLS | Se lee entera con la clave pública | RLS al crear la tabla, no después |
| Trabajar sobre la rama principal | Cada prueba a medias se publica | Una rama por cambio; Vercel te da su URL de prueba |
Un .env commiteado |
La clave queda en el historial para siempre | .gitignore desde el primer commit |
service, secret y key. Si
sale algo que no sea la clave anon de Supabase, tienes un problema esta misma tarde.
El mapa completo: qué hace cada pieza
Antes de tocar nada conviene tener el dibujo entero en la cabeza. Son cuatro piezas y cada una hace una sola cosa — y esa separación es la razón de que el conjunto se pueda mantener sin equipo.
| Pieza | La única pregunta que contesta | Lo que NO es |
|---|---|---|
| GitHub | «¿Qué decía este fichero hace tres semanas?» | No sirve la web. Un repositorio no es un servidor |
| Vercel | «¿Cómo llega esto a quien lo visita?» | No guarda datos. Cada visita empieza de cero |
| Supabase | «¿Dónde vive lo que hay que recordar?» | No es un backend entero. Es base de datos + cuentas |
| El agente de IA | «¿Quién escribe el código?» | No decide qué hay que construir. Eso es tuyo |
Git en diez minutos: los seis comandos que se usan
Git asusta porque tiene doscientos comandos. En la práctica se usan seis, y con esos seis se trabaja durante años. Lo demás es para cuando algo sale mal, y para eso está el que sabe o está la IA.
$ git status
# Qué he tocado. Se escribe ANTES de cualquier otra cosa.
$ git checkout -b arreglo-del-formulario
# Abre una rama. Todo lo que hagas aquí no toca lo publicado.
$ git add -A
$ git commit -m "Arregla el envio del formulario de contacto"
# Guarda un punto al que se puede volver. Con un mensaje que se entienda.
$ git push -u origin arreglo-del-formulario
# Sube la rama. Vercel te da una URL de prueba SOLO de esa rama.
$ git checkout main && git pull
# Vuelve a lo bueno y baja lo último. Antes de empezar otra cosa.Y las dos situaciones que asustan de verdad
| «He roto algo» | Qué se hace |
|---|---|
| He tocado un fichero y quiero dejarlo como estaba | git checkout HEAD -- ruta/del/ficheroNunca sobre el árbol entero: eso se lleva por delante todo lo que no esté commiteado |
| He publicado algo que está mal | Vercel guarda todos los despliegues. Se entra en el anterior y se pulsa «promover a producción». Son quince segundos y no hace falta Git |
La RLS, explicada de una vez
Es el concepto de Supabase que más se malentiende y el único donde equivocarse tiene consecuencias. Merece hacerlo despacio.
Supabase expone tu base de datos directamente a internet. Eso suena a locura hasta que se entiende la pieza que lo hace seguro: cada tabla lleva unas reglas que dicen, fila por fila, quién puede verla y quién puede tocarla. Eso es la RLS (seguridad a nivel de fila). No es un añadido: es el mecanismo.
create table recordatorios (
id uuid primary key default gen_random_uuid(),
user_id uuid not null default auth.uid(), -- ⚠️ lo pone el servidor
texto text not null,
creado_en timestamptz not null default now()
);
alter table recordatorios enable row level security;
-- Una política POR VERBO. Las cuatro, o falta una.
create policy "ver los mios" on recordatorios for select
using (auth.uid() = user_id);
create policy "crear los mios" on recordatorios for insert
with check (auth.uid() = user_id);
create policy "editar los mios" on recordatorios for update
using (auth.uid() = user_id);
create policy "borrar los mios" on recordatorios for delete
using (auth.uid() = user_id);for delete, Supabase no da error: responde que todo ha ido bien y no borra
nada. La fila desaparece de la pantalla porque el navegador se lo cree, y reaparece
al recargar. Es el fallo perfecto: no hay error, no hay traza, y la primera
persona que lo nota es un usuario.
.select('id')) y no toques la pantalla si vuelve vacío.
Con eso, un fallo de permisos se convierte en un mensaje de error de verdad en vez de en
una mentira silenciosa. Vale la misma regla para todo: si el servidor no confirma
que hizo algo, tu interfaz no puede decir que se hizo.
Las dos claves, y por qué una de ellas se puede publicar
anon | service_role | |
|---|---|---|
| ¿Dónde va? | En el navegador. Es pública por diseño | Sólo en el servidor, en variables de entorno |
| ¿Qué puede hacer? | Sólo lo que la RLS permita | Todo. Se salta la RLS entera |
| Si se filtra | No pasa nada | Han perdido la base de datos completa |
Las variables de entorno, sin misterio
Una variable de entorno es un dato que no está en el código y que el programa lee al arrancar. Es donde viven las claves, y hay tres sitios distintos donde ponerlas según para qué:
-
En tu ordenador: el fichero
.env.localPara trabajar en local. Va en el
.gitignoredesde el primer minuto, antes incluso de escribir nada dentro — así no existe la ventana en la que se sube por descuido. -
En Vercel: el panel de variables de entorno
Para producción. Se pegan ahí y no se vuelven a ver. Ojo al prefijo: en Vercel, una variable que empieza por
NEXT_PUBLIC_oVITE_se envía al navegador. Nunca metas ahí nada que deba quedarse en el servidor: el nombre lo dice, pero se lee rápido y se entiende tarde. -
En GitHub: los secrets del repositorio
Para lo que se ejecuta solo (las tareas programadas). Es otro sitio distinto, con otra lista, y hay que acordarse de que existe: una clave rotada en Vercel y no en GitHub deja la tarea nocturna fallando sin que nadie lo mire.
La primera semana, día a día
Con todo lo anterior en la cabeza, esto es lo que de verdad da resultado — y en qué orden, que importa más de lo que parece:
| Día | Qué haces | Qué has ganado |
|---|---|---|
| 1 | Repositorio, Vercel conectado, una página con tu nombre publicada | Tienes una URL que funciona. Es más de lo que parece: el resto son cambios |
| 2 | Una rama, un cambio, una URL de prueba, y lo fusionas | Ya sabes trabajar sin miedo |
| 3 | Supabase: una tabla con RLS y sus cuatro políticas | Sabes guardar datos y quién los ve |
| 4 | Alta y login. No lo escribas tú: Supabase lo trae | Tienes usuarios de verdad |
| 5 | Una función con una clave en variable de entorno | Ya puedes hablar con cualquier servicio sin exponer nada |
Antes de dar esto por aprendido
- Sé qué hace cada una de las cuatro piezas y qué pasa si falta.
- Distingo la clave anon (pública por diseño) de la service role (nunca sale del servidor).
- Activo RLS al crear la tabla, con una política por verbo.
- Trabajo en ramas y compruebo en la URL de prueba antes de publicar.
- He decidido —antes de montar nada— qué datos NO van a vivir ahí dentro.
← Volver a la escuela Siguiente: programar con Claude Code o Codex →