3. 🖼️ La foto: de localStorage a tu propio backend

Cuarenta minutos, el módulo más largo y el que da sentido a todo lo demás.

Diagrama del módulo 3: API Gateway, las tres Lambdas, DynamoDB y el bucket privado de S3 resaltados como nuevos; GitHub y Amplify ya existían desde el módulo 2

Todo lo que estaba en gris en el módulo 2 se prende aquí. Eso es lo que vas a construir, y lo va a escribir un agente mientras tú lo revisas.

El gancho, 5 minutos

Agrega tu foto y tu recuerdo, y luego abre tu altar en el teléfono

En tu laptop, agrégale a tu altar la foto de quien elegiste y un recuerdo escrito.

Ahora saca tu teléfono y abre tu URL de amplifyapp.com.

No está. Está el set tradicional, pero tu foto y tu recuerdo no.

Tu altar nunca estuvo en internet. La página sí, pero lo que le agregaste vivía en localStorage, o sea en el navegador de tu laptop. Eso es lo que vamos a arreglar, y para eso hace falta un backend.

El agente construye, 15 minutos

El starter trae una spec en .kiro/specs/ofrenda/. Abre tasks.md: la tarea 1 le pide al agente escribir la infraestructura, los handlers y el cambio de web/src/datos/almacen.js para mover los datos a la API. Kiro lee esa tarea junto con requirements.md y design.md, así que no tienes que explicarle nada en el chat.

¿Qué es una spec?

Una spec es la forma en que Kiro planea un cambio grande antes de escribir código. Son tres archivos:

  • requirements.md: qué tiene que hacer el altar, escrito como criterios que se pueden comprobar.
  • design.md: cómo se construye: la tabla, el bucket, las Lambdas y las rutas de la API.
  • tasks.md: los pasos, cada uno con los archivos que toca.

Normalmente Kiro la genera contigo a partir de una idea. Aquí ya viene escrita para que tu backend responda igual que lo que revisa npm run verify 3.

¿Por qué Kiro no despliega solo?

El starter trae una steering en .kiro/steering/workshop.md: reglas que Kiro lee en cada conversación dentro de este repo. Una de ellas le prohíbe correr deploy, bootstrap o destroy.

El agente escribe el código y lo valida con npm run synth y npm run build. El deploy lo corres tú, cuando ya revisaste lo que escribió.

🤖 Pídele al agente la tarea 1

En tasks.md, da clic en Start task arriba de la tarea 1.

Si no ves el botón, escríbelo en el chat de Kiro:

Haz la tarea 1 de .kiro/specs/ofrenda/tasks.md

Va a escribir infra/ofrenda-stack.ts, los handlers de lambda/ y la versión de nube de web/src/datos/almacen.js. Al final corre npm run synth y npm run build, que solo validan.

¿Qué es CDK y qué hace npm run synth?

CDK te deja describir la infraestructura en TypeScript. npm run synth convierte infra/ofrenda-stack.ts en una plantilla de CloudFormation, que es el formato que AWS sabe aplicar.

synth no crea nada en tu proyecto. Si termina sin error, la plantilla está bien formada; los recursos aparecen hasta que corres npm run deploy.

Mientras escribe, tú revisas. Estas son las preguntas que valen y dónde buscar la respuesta:

  • ¿El bucket quedó privado? Un bucket de imágenes no debe ser público. En infra/ofrenda-stack.ts busca BLOCK_ALL.
  • ¿Los permisos de datos apuntan a tu tabla y tu bucket? La policy básica de CloudWatch Logs es normal. Lo que no debe aparecer es una policy FullAccess o un permiso de DynamoDB o S3 con Resource: '*'. En infra/ofrenda-stack.ts busca grant: lo esperado son llamadas como grantReadData o grantPut sobre la tabla o el bucket.
  • ¿Listar usa Query o se fue a Scan? Scan lee toda la tabla y cuesta. Query lee solo tu altar. En lambda/listar.js busca QueryCommand; no debe haber ScanCommand.

Si alguna respuesta no es la esperada, díselo a Kiro con el archivo y lo que encontraste, y pídele que lo corrija antes de desplegar.

¿Qué es una policy y por qué importa Resource: '*'?

Una policy de IAM dice qué acciones puede hacer cada Lambda y sobre qué recursos. Resource: '*' significa “sobre cualquier recurso del proyecto”: si el código de esa Lambda tiene un error o alguien lo aprovecha, el daño alcanza cualquier tabla o bucket, no solo los del altar.

Los métodos grant de CDK escriben la policy apuntando únicamente a tu tabla o tu bucket.

💡 Si algo te da curiosidad, pregúntale a Kiro. Por ejemplo: Explícame qué hace infra/ofrenda-stack.ts, sin cambiar archivos.

Revisa los archivos que cambió el agente

Igual en Windows, macOS y Linux:

git status --short

Abre los archivos que aparecen en la salida y contesta las preguntas de arriba antes de ejecutar npm run diff. Los archivos nuevos aparecen con ??; también hay que abrirlos porque git diff todavía no los muestra.

Desplegar, 12 minutos

Mira qué va a cambiar antes de aplicarlo

Igual en Windows, macOS y Linux:

npm run diff -- --profile ofrenda

Ahora aplícalo

npm run deploy -- --profile ofrenda

CDK muestra los cambios de IAM antes de desplegar. Confirma que los permisos apuntan a la tabla y al bucket del altar; después escribe y y presiona Enter.

El deploy dice que no estás autorizado o que la operación no está disponible

Casi siempre es la Región. Compara la Región de tu perfil con la de AWS Settings. Igual en Windows, macOS y Linux:

aws configure get region --profile ofrenda

Si no coinciden, corrígela con aws configure set region TU-REGION --profile ofrenda y vuelve a desplegar.

CDK dice que el ambiente no tiene bootstrap

Te faltó el paso del módulo 2. Córrelo y vuelve a desplegar:

npx cdk bootstrap --profile ofrenda
CDK no encuentra credenciales o dice que tu sesión expiró

Vuelve a iniciar sesión con el perfil del workshop y repite el deploy:

aws login --profile ofrenda

Cuando acabe te imprime la URL de tu API. Apúntala.

💡 Cuenta los recursos

El agente escribió unos cuantos archivos. CloudFormation creó más recursos de los que aparecen como constructs: roles, permisos, logs y etapas de la API. Compara ambas listas para ver qué agrega CDK por debajo.

Mover el altar, 8 minutos

Ahora la parte del frontend. El único archivo que sabe dónde se guardan las cosas es web/src/datos/almacen.js, y eso es a propósito: ni un componente se toca. El hook que maneja el estado le pide los datos a ese archivo y no pregunta de dónde salieron.

Fíjate en el detalle que lo hace posible: las cuatro funciones son async desde el primer día, aunque localStorage sea síncrono. Si no lo fueran, cambiar a fetch obligaría a tocar todo lo que las llama.

Publica el cambio de la capa de datos

Igual en Windows, macOS y Linux:

git add infra lambda web/src/datos/almacen.js
git commit -m "Mover el altar a AWS"
git push origin main

Amplify necesita ese commit porque construye desde GitHub.

Pon tu URL de API en Amplify y redespliega

En la consola de Amplify, en las variables de entorno de tu app, agrega VITE_API_URL con la URL que te dio el deploy. Luego dale redeploy.

La URL queda fuera del repo. Cuando termine el redeploy, recarga primero el altar en tu laptop: esa primera carga importa lo que ya tenías en localStorage. Espera a ver tu foto y tu recuerdo antes de abrir el teléfono.

Comprueba el backend

npm run verify 3 https://tu-api.execute-api.tu-region.amazonaws.com/v1

Cambia la URL por la que imprimió npm run deploy.

Prueba CORS, crea dos elementos, los lista, sube y descarga una imagen real, revisa validaciones y confirma que puede borrar el segundo elemento.

npm run verify 3 marca una línea con ✗

Cada línea es una prueba, y la que sale con ✗ dice qué esperaba. Cópiala y pásasela a Kiro:

npm run verify 3 falla con este mensaje: <pega la línea>.
Revisa el handler contra .kiro/specs/ofrenda/design.md sin desplegar.

Revisa el diff, despliega otra vez y repite el checkpoint. Si el mensaje habla de CORS o de la URL, confirma que copiaste la URL completa que imprimió npm run deploy, incluido el /v1 final.

Vuelve a abrir tu altar en el teléfono

Y ahora sí está.

Checkpoint

Antes del descanso

  1. npm run verify 3 <url-de-tu-api> pasa.
  2. Tu altar en el teléfono muestra lo que agregaste en la laptop.
  3. El banner del altar ya no dice que guarda en el navegador.

Si te atoraste

Primero pégale el error a Kiro, con el comando que lo produjo, y pídele que te explique qué pasó sin desplegar ni borrar nada. Si la respuesta no te sirve, cambia de modelo en el selector del chat y vuelve a preguntar.

Si el descanso está por empezar y tu backend sigue sin pasar, usa la rama de rescate del módulo 3. Copia la solución a tu main sin borrar lo que llevas; los comandos están en Comandos del repo.