Aplicaciones concretas de la nube
En las cinco unidades anteriores recorrimos qué es la nube, cómo se virtualiza el cómputo, qué leyes rigen las arquitecturas distribuidas, qué metodologías permiten construir con ese material y, por último, cómo se integra la inteligencia artificial al mismo stack. Esta unidad cierra el arco mirando la pregunta práctica: ¿cómo se combinan todas esas piezas para construir un producto real? Vamos a recorrer el stack típico de una aplicación moderna, los servicios que casi cualquier producto necesita para hablar con sus usuarios y cobrarles, las plataformas que aceleran drásticamente el time-to-market y la forma de documentar lo que se va a construir. La motivación es directa: en pocos días vas a tener que diseñar e implementar tu propio prototipo, y este es el mapa que conecta los conceptos del curso con el catálogo de servicios disponibles.
1. De los conceptos al producto
Hay un salto incómodo entre saber qué es la computación en la nube y usar la nube para resolver un problema concreto. La teoría te da el vocabulario —IaaS, PaaS, SaaS, contenedores, regiones, eventual consistency— pero cuando te sentás frente a una idea de producto la pregunta es siempre la misma: ¿con qué piezas la armo?. Las decisiones se vuelven menos sobre conceptos y más sobre tradeoffs específicos: si elijo Stripe en vez de Mercado Pago pierdo cobertura local pero gano integración global; si uso Firebase me ahorro armar auth pero quedo atado a Google Cloud; si voy serverless pago por uso pero asumo cold starts.
La buena noticia es que casi todas las aplicaciones modernas se construyen combinando un puñado de servicios estándar. Hay un menú bastante estable de piezas —cómputo, base, storage, auth, canales de comunicación, pagos, integración con IA— y la mayoría del trabajo arquitectónico consiste en elegir una opción de cada categoría según el problema. Una vez que se internaliza ese menú, diseñar un nuevo producto se parece más a armar un lego conocido que a inventar algo desde cero. Esta unidad presenta el menú pieza por pieza.
Una aplicación cloud no es un servicio nuevo: es la composición de servicios existentes.
La idea de fondo
La pregunta interesante no es "¿qué construyo desde cero?" sino "¿qué combino?". El diferencial de tu producto vive en la lógica que pegás sobre los servicios, no en reimplementar lo que ya está resuelto (auth, pagos, mensajería). Saber qué hay en el catálogo es la mitad del trabajo de diseño.
Para tener en cuenta
- El catálogo de la pestaña Recursos de este curso es exactamente ese menú: cada item es una pieza típica de una aplicación moderna.
- Diseñar un prototipo es elegir 3 o 4 piezas del catálogo y articularlas; rara vez hace falta inventar una categoría nueva.
2. El stack típico de una app moderna
Casi cualquier aplicación que se monta hoy comparte un esqueleto de servicios. No todos están siempre presentes, pero el patrón se repite con tanta frecuencia que conviene tenerlo memorizado como punto de partida. Cuando alguien describe una idea de producto —"un marketplace para artesanos", "un bot que reserva turnos", "un dashboard de ventas"— se puede recorrer mentalmente el esqueleto y ya empezar a anticipar qué piezas va a necesitar y dónde van a estar los puntos sensibles.
El esqueleto típico tiene siete capas y todas resuelven preguntas distintas. Dónde corre el código se resuelve con un VPS, un container en una plataforma gestionada, o funciones serverless según cuánto control y cuánta comodidad queramos. Dónde guardamos datos estructurados se resuelve con una base de datos gestionada. Dónde guardamos archivos se resuelve con object storage. Quién es el usuario se resuelve con un servicio de autenticación. Cómo le hablamos al usuario fuera de la app con email transaccional y/o mensajería. Cómo cobramos con una pasarela de pagos. Y cómo entregamos contenido cerca del usuario con un CDN. Después aparecen capas opcionales según el caso: cache para acelerar lecturas, colas para desacoplar trabajos pesados, integración con IA cuando el producto tiene un componente conversacional o de análisis automático.
Una forma útil de pensar el stack es como una línea de montaje donde cada servicio cumple un rol específico y las decisiones de arquitectura están en cómo se comunican entre sí. La línea típica es: el navegador del usuario habla con el CDN (que cachea los assets estáticos), el CDN reenvía al backend si hace falta lógica dinámica, el backend valida la sesión contra el servicio de auth, lee y escribe en la base de datos, sube archivos al object storage, encola tareas pesadas en una cola, dispara correos o mensajes para notificar al usuario y, si corresponde, cobra a través de la pasarela de pagos.
3. Identidad y cobro: los servicios al usuario
De todas las piezas del stack, dos suelen aparecer en cualquier producto que tenga usuarios humanos del otro lado: autenticación y, si hay monetización directa, pagos. Las dos son territorio resuelto por la industria hace tiempo y, sin embargo, las dos son lugares donde un equipo bien intencionado puede meterse en problemas serios si decide reinventar la rueda.
Autenticación
Manejar usuarios y sesiones parece simple: registro, login, recuperación de contraseña, sesión persistente. En la práctica es uno de los componentes con más superficie de ataque y más casos borde: hash correcto de contraseñas, verificación de email, MFA, login social con proveedores externos, manejo de tokens, expiración de sesiones, invalidación, sincronización entre dispositivos, recuperación cuando el usuario perdió el segundo factor. Hacer todo eso bien lleva meses; hacerlo medio bien suele terminar en una filtración de credenciales.
Por eso la recomendación práctica es delegar: usar un servicio de autenticación gestionado como Auth0, Clerk, AWS Cognito o Supabase Auth, o aprovechar la auth integrada de un BaaS como Firebase. El proveedor se encarga del flujo completo, expone un SDK para el frontend y emite tokens que tu backend valida. El tradeoff es lock-in: salir después de Auth0 implica re-migrar usuarios y reescribir el flujo.
Pagos
Cobrar online tiene la misma lógica: el cumplimiento PCI-DSS, la integración con tarjetas y bancos, la disputa de chargebacks y el manejo de fraude son tareas que llevan años de inversión y certificación. La decisión real al elegir una pasarela de pagos es entre opciones globales (Stripe, Square) que dan cobertura amplia y APIs limpias, y opciones locales (Mercado Pago, dLocal, Ualá Bis) que tienen mejor adopción en países específicos y soportan métodos como Rapipago, Pix o transferencias inmediatas. Para audiencia argentina típicamente conviene Mercado Pago; para vender a clientes globales, Stripe.
Qué suele pasar
Para "ahorrar un paso" al usuario, alguien decide guardar el número de tarjeta o un token sensible en la base de datos del producto. A las semanas hay una auditoría, una filtración o simplemente una multa de tu adquirente.
Por qué
El estándar PCI-DSS regula con detalle qué se puede y qué no se puede almacenar; cumplirlo desde cero es carísimo. La pasarela existe para que vos nunca veas el dato sensible: solo manejás un token opaco emitido por el proveedor.
Cómo evitarlo
Usar las APIs de tokenización que vienen incluidas en cualquier pasarela. Lo único que guardás en tu base es el token devuelto por el proveedor; el dato sensible nunca toca tus servidores.
4. Hablarle al usuario sin que entre a tu app
Una vez que el usuario está registrado y eventualmente paga, el producto necesita comunicarse con él en momentos donde no está usando activamente la aplicación: confirmar un signup, mandar un recibo, recordarle un turno, avisarle que su pedido salió. Hay tres canales principales y cada uno tiene su lógica propia: correo electrónico, mensajería instantánea (típicamente WhatsApp o Telegram en Latam) y notificaciones push dentro de la app.
El correo transaccional se delega a un servicio de mailing como Postmark, Resend o SendGrid. Estos proveedores se ocupan de la entregabilidad —reputación de IP, autenticación SPF/DKIM/DMARC, manejo de bounces y complaints—, cosas que mandando mails desde tu propio SMTP no escalan más allá de unos cientos por día. El correo es el canal por defecto para comunicación no urgente: bienvenidas, recuperación de password, notificaciones, recibos, resúmenes periódicos.
La mensajería en cambio se reserva para comunicación urgente o conversacional. WhatsApp tiene tasas de apertura cercanas al 90% y permite bots interactivos; el costo por mensaje es órdenes de magnitud más alto que el mail. Twilio, MessageBird, 360dialog son los proveedores típicos para WhatsApp Business; Telegram ofrece su Bot API gratis y es ideal para prototipos. SMS sigue vivo donde hace falta llegar a usuarios sin smartphone o donde la verificación por número de teléfono es obligatoria.
Empezá siempre por mail transaccional. Es 10 a 50 veces más barato que WhatsApp por mensaje, no requiere alta como Business Account y cubre la mayoría de los casos. Sumá WhatsApp cuando tengas evidencia de que la audiencia no lee el correo o cuando la conversación bidireccional sea parte central del producto (un bot de turnos, una atención al cliente).
5. Datos más allá de la base relacional
En la Unidad 3 vimos que el dato típico de una aplicación vive en una base de datos relacional o documental: filas, columnas, índices, consistencia gestionada por el motor. Pero en cualquier producto real aparecen dos tipos de datos que no encajan en una base y que necesitan su propia infraestructura: archivos y datos externos que no son nuestros.
Object storage para archivos
Cualquier app con uploads necesita un lugar para archivos: avatares, documentos, PDFs subidos por el usuario, fotos de evidencia, videos grabados. Guardar archivos en la base relacional es un error clásico (infla las tablas, complica los backups, encarece las queries). El patrón correcto es separar: el archivo binario va a un servicio de object storage como S3, Cloud Storage, R2 o un Supabase Storage; la base de datos guarda solamente la referencia (path, URL, key) junto con los metadatos del archivo (tamaño, tipo, fecha, dueño).
Object storage tiene además una propiedad útil para servir contenido público: cada bucket puede exponerse detrás de un CDN, de manera que las imágenes se sirven desde el nodo más cercano al usuario sin tocar tu backend. El flujo típico para un upload es: el frontend pide una URL firmada al backend, sube directamente al bucket usando esa URL, y avisa al backend con la key del archivo subido. El backend nunca recibe el binario completo, solo el metadato.
Scraping para datos externos
Hay productos cuyo valor depende de información que vive en sitios web ajenos sin API: precios de la competencia, listados de eventos culturales, publicaciones inmobiliarias, contenido público para armar un buscador o para alimentar un RAG. Cuando no hay feed oficial, la alternativa es scraping: navegar y parsear el HTML como lo haría un usuario humano, pero programáticamente.
El stack típico de scraping va de menor a mayor complejidad: una librería como BeautifulSoup o Scrapy para sitios estáticos, un browser headless como Playwright o Puppeteer para sitios que renderizan con JavaScript, y un servicio gestionado como Bright Data o ScrapingBee cuando hace falta rotar proxies o resolver CAPTCHAs a escala. La complejidad real no suele ser técnica sino legal y operativa: cumplir términos de uso del sitio fuente, mantener el scraper cuando el HTML cambia, evitar bans por volumen.
6. Acelerar con plataformas todo-en-uno
Hasta acá presentamos cada pieza del stack por separado. Esa aproximación —elegir un servicio por categoría— da el máximo control y la mejor portabilidad, pero también pide más tiempo de integración: cada componente tiene su SDK, sus credenciales, su lógica de autenticación, su modelo de costos. Para muchos productos —sobre todo MVPs, prototipos y herramientas internas— el tiempo importa más que el control. Para esos casos existen plataformas que integran varias piezas en un mismo proveedor: BaaS y low-code.
BaaS: el backend como producto
Una plataforma de Backend as a Service como Firebase, Supabase o Convex te entrega en un único SDK auth, base de datos (con sync en tiempo real, en muchos casos), object storage, funciones serverless, hosting estático y notificaciones push. El cliente —web, iOS, Android— habla directamente con los servicios usando el SDK; del lado del producto solo modelás el dominio y la UI. Una app que armada pieza por pieza llevaría dos semanas suele estar funcionando en un día con BaaS.
El tradeoff es lock-in. Salir de Firestore o Convex después suele ser reescribir, no migrar: las queries, el modelo de datos y los patrones de sincronía son muy específicos. Supabase mitiga esto porque por abajo es PostgreSQL estándar, lo que facilita salirse eventualmente; Firebase está más fuertemente atado a Google Cloud. El otro tradeoff es el costo a escala: el pricing por reads/writes/egress se acumula rápido si el producto crece.
Low-code: ni siquiera escribir el SDK
Las plataformas low-code y no-code —Bubble, Webflow, Retool, FlutterFlow, las más recientes Lovable y v0— llevan la lógica un paso más allá: en vez de escribir código contra un SDK, armás la aplicación arrastrando componentes en una interfaz visual o describiéndola en lenguaje natural. Para casos como herramientas internas (un CRM simple, un panel de admin), MVPs para validar una idea o automatizaciones entre SaaS, es la opción más rápida. Para productos con lógica compleja, performance crítica o requisitos de portabilidad, no es viable.
Stack pieza por pieza vs plataforma todo-en-uno
Stack pieza por pieza
- Control total: cada pieza es la mejor de su categoría.
- Portabilidad: cambiar un componente no obliga a reescribir el resto.
- Más tiempo de integración: cada SDK tiene su lógica propia.
- Más superficie operativa: backups, monitoreo, billing en varios proveedores.
Plataforma todo-en-uno (BaaS / low-code)
- Time-to-market muy corto: días en vez de semanas.
- Una sola facturación, un solo SDK, un solo proveedor.
- Lock-in fuerte: salir es reescribir, no migrar.
- Pricing puede dispararse a escala.
7. Agentes IA en producción
La Unidad 5 introdujo los LLMs y RAG: el modelo recibe un prompt, eventualmente acompañado de contexto recuperado de una base vectorial, y devuelve texto. Ese patrón cubre buena parte de los productos con IA actuales (chatbots, asistentes de búsqueda, generadores de contenido). Pero hay una segunda generación de productos donde el LLM no solo responde: actúa. Lee archivos, consulta bases de datos, llama APIs, edita código, manda mails, agenda reuniones. Es lo que se conoce como agentes: un LLM más una caja de herramientas (tools) que puede invocar a voluntad para resolver una tarea.
Construir un agente requiere dos cosas además del modelo: exponer las tools (funciones que el modelo puede llamar, cada una con su schema de input/output) y manejar el bucle de razonamiento (el modelo decide qué tool llamar, recibe el resultado, decide si necesita otra, hasta que considera resuelta la tarea). Cada proveedor de LLM tiene su API de tool calling: OpenAI lo llama function calling, Anthropic lo llama tool use. Funcionan parecido y se programan a mano para cada agente.
MCP: el protocolo estándar para tools
El problema con armar tools a mano es que cada agente queda atado a las suyas y no son reutilizables. Si un equipo expone un acceso a su base de datos como tool para su agente propio, y otro equipo quiere darle al suyo el mismo acceso, tiene que reimplementar la integración. MCP (Model Context Protocol), publicado por Anthropic a fines de 2024, resuelve eso: estandariza cómo un cliente (Claude Code, Claude Desktop, Cursor, Windsurf, Zed) descubre y llama tools expuestas por un server MCP. Cualquier cliente compatible puede usar cualquier server compatible.
En la práctica, MCP permite "agentizar" un LLM con tools propias sin escribir glue code para cada cliente. Hay servers oficiales listos para filesystem, GitHub, Slack, Postgres, Google Drive, Sentry y otros; cualquier equipo puede escribir uno propio para su dominio. Para un prototipo del challenge, MCP es interesante cuando el producto es un asistente que necesita actuar sobre los datos del docente, del alumno o de la institución: leer submissions, consultar calificaciones, redactar devoluciones.
Un chatbot responde; un agente actúa. La diferencia es tener tools.
El primer paso al diseñar un producto con IA es preguntarse si alcanza con un LLM puro (toma prompt, devuelve texto) o si el modelo necesita ejecutar acciones en el mundo. Si la respuesta es la segunda, vas a estar construyendo un agente, y vas a necesitar pensar el set de tools que le exponés.
Para tener en cuenta
- Los agentes amplifican errores: si una tool ejecuta una acción destructiva, el modelo puede invocarla incorrectamente. Diseñar el set de tools incluye decidir cuáles requieren confirmación humana.
- MCP es la opción estándar cuando ya tenés varios clientes o querés que terceros extiendan tu app; para un agente único con dos tools, el tool calling nativo del proveedor alcanza.
8. Documentar lo que vas a armar
La última pieza del puente entre concepto y producto no es técnica sino documental. Antes de tirar el primer container, conviene haber escrito dos documentos cortos que después facilitan la construcción y el mantenimiento: el PRD (Product Requirements Document) y el ADR (Architectural Decision Record). Los dos son centrales para la entrega del challenge final del curso.
PRD: qué vamos a construir
El PRD define el producto antes de pensar en cómo construirlo: qué problema resuelve, para qué usuario, con qué alcance, con qué criterio de éxito. No es un documento largo —una a tres páginas bien escritas alcanzan— pero es el filtro que evita construir cosas que nadie necesita. Atlassian tiene una guía canónica para escribir PRDs que es la referencia incluida en la pestaña Bibliografía de este curso.
ADR: por qué construimos así
El ADR registra las decisiones arquitectónicas importantes: para cada elección de stack (qué base de datos, qué auth, qué cómputo, qué pasarela de pagos), por qué la elegimos, qué alternativas evaluamos y qué tradeoffs aceptamos. Su valor real aparece seis meses después, cuando alguien (vos mismo, otro desarrollador) abre el proyecto y necesita entender por qué el sistema es como es. AWS publica una prescriptive guidance sobre ADRs que también está en la pestaña Bibliografía.
Diagram as code: el diagrama que no se desactualiza
Un ADR sin diagrama es difícil de leer; un diagrama subido como PNG a Confluence es difícil de mantener. La solución es diagram as code: lenguajes textuales como Mermaid, PlantUML o D2 que se renderizan automáticamente y viven en el repo junto al código. Mermaid en particular tiene la ventaja de que GitHub lo renderiza directo en cualquier archivo Markdown, así que un diagrama de arquitectura metido en el README se ve sin ningún paso adicional. Para el ADR del challenge, un diagrama Mermaid bien hecho vale por varios párrafos de prosa.
9. Caso integrador: bot de WhatsApp para turnos
Para terminar de bajar a tierra todo lo anterior, repasemos un caso completo a nivel de diseño. El producto es un bot de WhatsApp que permite a un consultorio médico recibir y gestionar turnos sin que la secretaria atienda teléfono. El paciente conversa con el bot en lenguaje natural ("hola, quiero un turno con la doctora para la semana que viene a la tarde"), el bot interpreta la intención, propone horarios disponibles, registra la reserva y manda un recordatorio por mail el día previo. Es un caso simple pero combina cinco piezas distintas del catálogo y obliga a tomar decisiones reales.
Las piezas elegidas y por qué
Canal de entrada: messaging (Twilio para WhatsApp Business). Twilio porque tiene buena documentación, proceso de alta razonablemente rápido y SDK en todos los lenguajes. Alternativa descartada: 360dialog (más barato a escala pero proceso de alta más lento).
Interpretación del lenguaje: AI integration (Claude Haiku). Haiku porque es más que suficiente para extraer intención y entidades de un mensaje corto, y cuesta una fracción de Sonnet u Opus. Alternativa descartada: GPT-5 Mini (similar precio pero el equipo ya tiene experiencia con la API de Anthropic).
Persistencia: database gestionada (Supabase Postgres). Supabase porque viene con Postgres real, dashboard incluido y nivel gratis suficiente para el prototipo. Alternativa descartada: Firestore (más rápido para empezar pero peor para queries por fecha y disponibilidad).
Recordatorios: mailing transaccional (Resend). Resend porque la API es simple, el nivel gratis cubre los 3.000 mails mensuales esperados y la integración desde Node es de cinco líneas. Alternativa descartada: mandar el recordatorio por WhatsApp (más caro por mensaje y, para un simple recordatorio diario, no aporta).
Cómputo: serverless (Vercel Functions). Vercel porque hostea también el panel web de administración del consultorio (que es Next.js), así que un solo deploy cubre web + webhooks de WhatsApp. Alternativa descartada: un contenedor en Fly.io (más control pero más overhead para algo que recibe pocos eventos al día).
El flujo, en un diagrama
El siguiente es el diagrama Mermaid que iría dentro del ADR. En GitHub se renderiza automáticamente; en otras plataformas se puede incluir el SVG generado.
sequenceDiagram
participant U as Paciente (WhatsApp)
participant T as Twilio
participant F as Vercel Function
participant C as Claude Haiku
participant DB as Supabase
participant R as Resend (día previo)
U->>T: "quiero turno la semana que viene a la tarde"
T->>F: webhook con el mensaje
F->>C: extraer intención + fecha/hora
C-->>F: { intent: "reservar", preferencia: "tarde, próxima semana" }
F->>DB: consultar disponibilidad
DB-->>F: horarios libres
F->>T: enviar opciones al paciente
T->>U: "tengo martes 16hs o jueves 18hs"
U->>T: "martes"
T->>F: webhook con confirmación
F->>DB: crear turno
F->>T: confirmar al paciente
Note over R,U: 24h antes del turno
R->>U: recordatorio por mail
El diagrama vive en el repo junto al ADR; cualquier cambio en el flujo se traduce en un commit que toca también el diagrama.
Lo que faltaría discutir en el ADR completo
Este es solo el esqueleto del walk-through. Un ADR real para este producto tendría que cubrir también: cómo se autentican las requests de Twilio para que nadie pueda simular un mensaje, cómo se manejan los conflictos cuando dos pacientes piden el mismo horario al mismo tiempo, qué pasa si Claude devuelve una interpretación errónea, qué se hace si el paciente quiere cancelar, dónde se loguean los mensajes para auditoría futura. Cada una de esas preguntas es una decisión arquitectónica que merece quedar registrada.