Tienes el problema elegido, el alcance acotado, el límite de coste fijado y el repositorio creado. Lo que no tienes todavía es un solo recurso en Google Cloud, y eso es intencionado.

Esta lección es la que más veces se salta y la que más caro sale saltarse. Diseñar antes de teclear no es un ritual académico: es la respuesta racional a un hecho técnico incómodo de la nube. Hay decisiones que se toman en treinta segundos y se pagan durante años.

El projectId no se puede cambiar. Nunca. Si creas mi-proyecto-test-2 porque tenías prisa, ese identificador aparecerá en cada comando, en cada URL de la consola, en cada log, en cada línea de la factura y en la captura de pantalla que enseñes en una entrevista. Cambiarlo significa recrear todo lo que hay dentro.

El rango CIDR de una subred no se puede reducir. La región de un bucket no se puede cambiar. Migrar de Firestore a Cloud SQL —o al revés— significa reescribir la capa de datos entera. El esquema de una tabla particionada de BigQuery admite añadir columnas pero no cambiar la clave de partición sin recrearla.

Ninguna de esas decisiones es difícil. Todas son irreversibles. Y por eso se toman con un folio delante, no con la consola abierta.

Al terminar esta lección tendrás el plano completo de tu sistema: qué componentes lógicos existen, qué servicio de GCP implementa cada uno y por qué ese y no el alternativo, cómo se llaman las cosas, quién puede hablar con quién, quién tiene permiso para qué, dónde vive cada dato y cuánto tiempo, cuánto va a costar el mes que viene, qué vas a medir para saber si funciona, y las decisiones importantes escritas en un formato que dentro de seis meses seguirá teniendo sentido.

Contenido

  1. Por qué se diseña antes de teclear, y qué es "suficiente diseño"
  2. De los requisitos a los componentes lógicos
  3. De los componentes lógicos a los servicios de GCP
  4. Los tres diagramas que sirven
  5. Diseño de la estructura organizativa
  6. Convención de nombres y de etiquetas
  7. Diseño de la red
  8. Diseño de la identidad
  9. Modelo de datos y ciclo de vida del dato
  10. Estimación de coste previa
  11. Definición de los SLO del proyecto
  12. Decisiones de arquitectura documentadas (ADR)
  13. Revisión del diseño antes de implementar
  14. El diseño completo de RefugioReserva

  1. Por qué se diseña antes de teclear, y qué es "suficiente diseño"

El argumento del coste del cambio

La razón de diseñar no es "hacer las cosas bien". Es que el coste de cambiar una decisión crece de forma brutal con el momento en que la cambias:

Decisión Cambiarla en el diseño Cambiarla tras implementar Cambiarla en producción
Nombre del proyecto 10 segundos Recrear todo Imposible en la práctica
Rango de subred 10 segundos Recrear la red y lo que hay dentro Ventana de mantenimiento
Firestore ↔ Cloud SQL 1 minuto Reescribir la capa de datos (~15 h) Migración con datos vivos
Región 10 segundos Recrear todo Migración completa
Cloud Run ↔ GKE 1 minuto Reescribir despliegue (~8 h) Migración con tráfico
Clave de partición en BigQuery 10 segundos Recrear tabla y recargar Recrear + huecos en el panel
Añadir un campo a una tabla 10 segundos 20 minutos 20 minutos

Las filas de arriba son las que justifican el diseño. La de abajo es la que justifica no diseñar de más: añadir un campo cuesta lo mismo antes que después, así que no pierdas una hora decidiendo si el campo notas debe existir.

Qué es "suficiente diseño" para un proyecto de este tamaño

El diseño tiene rendimientos decrecientes muy rápidos. Para un proyecto de 50 horas:

Nivel de diseño Tiempo Qué produce Veredicto
Ninguno 0 h Empiezas a teclear Acabas rehaciendo el 40 %
Suficiente 5-8 h Los nueve artefactos de esta lección ✅ Lo correcto
Excesivo 25 h Diagramas UML, especificación de cada endpoint, modelo de amenazas formal Nunca llegas a construir

Los nueve artefactos del "suficiente diseño", y ninguno ocupa más de una página:

# Artefacto Responde a Tiempo
1 Lista de componentes lógicos ¿De qué piezas consta? 30 min
2 Tabla componente → servicio con justificación ¿Con qué se implementa cada pieza y por qué? 1 h
3 Tres diagramas (contexto, componentes, despliegue) ¿Cómo encaja todo? 1,5 h
4 Estructura de proyectos y convención de nombres ¿Cómo se llama y dónde vive cada cosa? 30 min
5 Plan de red + matriz de flujos ¿Quién habla con quién? 45 min
6 Tabla de identidades y roles ¿Quién puede hacer qué? 45 min
7 Modelo de datos + ciclo de vida ¿Qué se guarda dónde y hasta cuándo? 1 h
8 Estimación de coste ¿Cabe en el límite? 45 min
9 SLI/SLO + ADR ¿Cómo sé que funciona y por qué decidí esto? 1 h

La regla que decide si un diseño está terminado: cuando puedas responder, sin dudar y sin abrir la consola, a estas cinco preguntas:

  1. ¿Cuánto va a costar al mes y por qué?
  2. ¿Qué pasa si el componente más importante se cae?
  3. ¿Quién puede leer los datos de los usuarios?
  4. ¿Qué servicio elegiste y qué descartaste, y por qué?
  5. ¿Cómo sabrás si está funcionando bien sin que te lo diga nadie?

Si dudas en alguna, ahí es donde falta diseño.

  1. De los requisitos a los componentes lógicos

Antes de nombrar un solo servicio de Google, describe tu sistema en componentes lógicos: piezas funcionales, agnósticas de proveedor. Este paso parece burocrático y es el que evita el error más común del principiante, que es diseñar la arquitectura como una lista de productos que le apetece usar.

Seis familias de componentes cubren prácticamente cualquier proyecto de este módulo:

flowchart TB
    subgraph Frontal["Frontal — exposición al usuario"]
        F1["Punto de entrada público<br/>TLS, dominio, caché, filtrado"]
    end
    subgraph Servicio["Servicio — la lógica"]
        S1["Aplicación web / API"]
        S2["Trabajos asíncronos<br/>y programados"]
    end
    subgraph Almacen["Almacenamiento"]
        A1["Objetos<br/>ficheros, imágenes"]
        A2["Base de datos operativa<br/>estado del negocio"]
    end
    subgraph Datos["Datos y analítica"]
        D1["Transporte de eventos"]
        D2["Almacén analítico"]
        D3["Visualización"]
    end
    subgraph IA["Inteligencia"]
        I1["Modelo o API de IA"]
    end
    subgraph Op["Operación"]
        O1["Identidad y secretos"]
        O2["Observabilidad"]
        O3["Entrega continua"]
        O4["Infraestructura como código"]
    end

    F1 --> S1
    S1 --> A1
    S1 --> A2
    S1 --> D1
    S2 --> A2
    D1 --> D2
    D2 --> D3
    S1 --> I1
    O1 -.-> S1
    O2 -.-> S1
    O3 -.-> S1
    O4 -.-> F1

Cómo se rellena esto para tu proyecto. Coge tus requisitos funcionales de 08-01 y escribe, para cada componente, qué hace en tu dominio:

Componente lógico Qué hace en mi proyecto ¿Obligatorio?
Punto de entrada público Sí (RNF-5)
Aplicación web / API Sí (RF-1)
Trabajos asíncronos Sí (RF-4)
Almacenamiento de objetos Sí (RF-2)
Base de datos operativa Sí (RF-3)
Transporte de eventos Sí (RF-4)
Almacén analítico Sí (RF-5)
Visualización Sí (RF-5)
IA Sí (RF-6)
Identidad y secretos Sí (RNF-3, RNF-4)
Observabilidad Sí (RNF-6, RNF-7)
Entrega continua Sí (RNF-2)
IaC Sí (RNF-1)

Si alguna casilla te sale forzada —"pues aquí pondría Pub/Sub porque hay que poner algo"— es una señal de que el problema elegido no ejercita esa capa de forma natural. Dos salidas legítimas: cambiar ligeramente el problema para que la necesite, o implementar la versión más sencilla posible del componente y documentar en un ADR que es deliberadamente mínima. Lo que no vale es meter un servicio complejo sin motivo: eso puntúa negativo en el bloque A de la rúbrica, no positivo.

  1. De los componentes lógicos a los servicios de GCP

Ahora sí, la traducción. Para cada componente, una fila con cuatro columnas obligatorias: servicio elegido, por qué, qué descartaste y por qué lo descartaste.

Esa cuarta columna es el 50 % del bloque A de la rúbrica. Un entrevistador no te pregunta "¿usaste Cloud Run?"; te pregunta "¿por qué Cloud Run y no App Engine?". Si no lo escribiste el día que lo decidiste, no lo vas a recordar.

El árbol de cómputo (de 02-07)

flowchart TD
    A["¿Qué necesito ejecutar?"] --> B{"¿Es código de<br/>petición-respuesta<br/>en un contenedor?"}
    B -- Sí --> C{"¿Necesito control<br/>del clúster, operadores<br/>o malla de servicios?"}
    C -- No --> D["✅ Cloud Run<br/>Escala a cero. Recomendado por defecto"]
    C -- Sí --> E{"¿Justificado por escrito<br/>y cabe en el presupuesto?"}
    E -- No --> D
    E -- Sí --> F["GKE Autopilot"]
    B -- No --> G{"¿Reacciona a un evento<br/>y es una sola función?"}
    G -- Sí --> H["✅ Cloud Functions<br/>(gen 2 = Cloud Run por debajo)"]
    G -- No --> I{"¿Es un proceso<br/>que empieza y termina?"}
    I -- Sí --> J["✅ Cloud Run Jobs<br/>+ Cloud Scheduler"]
    I -- No --> K{"¿Necesito el sistema<br/>operativo, GPU o software<br/>que no se contenedoriza?"}
    K -- Sí --> L["Compute Engine"]
    K -- No --> D

Para el 90 % de los proyectos de este módulo, la respuesta es Cloud Run. Y la razón principal no es técnica sino económica: escala a cero. Un proyecto de portafolio recibe tráfico cero el 99 % del tiempo, y todo lo que no escala a cero te come el presupuesto de 08-01 sin dar nada a cambio.

El árbol de base de datos (de 02-06 y 02-03)

flowchart TD
    A["¿Cómo son mis datos?"] --> B{"¿Hay relaciones,<br/>y necesito transacciones<br/>entre varias entidades?"}
    B -- Sí --> C{"¿Necesito escala<br/>global o >10 TB?"}
    C -- No --> D["✅ Cloud SQL<br/>PostgreSQL / MySQL"]
    C -- Sí --> E["Spanner<br/>⚠️ caro para un portafolio"]
    B -- No --> F{"¿Acceso por clave,<br/>documentos, sin<br/>consultas complejas?"}
    F -- Sí --> G{"¿Quiero coste cero<br/>en reposo?"}
    G -- Sí --> H["✅ Firestore<br/>Escala a cero de verdad"]
    G -- No --> H
    F -- No --> I{"¿Series temporales<br/>de gran volumen?"}
    I -- Sí --> J["Bigtable<br/>⚠️ caro para un portafolio"]
    I -- No --> D

La disyuntiva real de este módulo es Cloud SQL frente a Firestore, y tiene una dimensión económica que hay que poner sobre la mesa:

Cloud SQL (db-f1-micro) Firestore
Coste en reposo ~7-9 €/mes siempre encendida 0 € (nivel gratuito generoso)
Transacciones multi-entidad ✅ Nativas y sencillas ⚠️ Posibles, más limitadas
Consultas con JOIN y agregación ✅ SQL completo ❌ No hay JOIN
Modelo de datos Relacional normalizado Documentos, se desnormaliza
Curva si vienes de SQL Nula Media
Exportación a BigQuery Federación / volcado Extensión nativa a BigQuery
Encaja bien si… Tu dominio tiene reglas de integridad Tu dominio es "documentos con estado"

Si tu límite de coste es 0 €, la decisión está tomada: Firestore. Si tienes 10-15 € y tu dominio tiene integridad referencial de verdad (como una reserva que no puede exceder la capacidad), Cloud SQL te lo pone mucho más fácil y la decisión se justifica sola.

El árbol de datos (de 04-01 y 04-04)

flowchart TD
    A["¿Qué hago con los datos?"] --> B{"¿Necesito reaccionar<br/>a un hecho cuando ocurre?"}
    B -- Sí --> C["✅ Pub/Sub<br/>topic + suscripción"]
    C --> D{"¿La transformación<br/>es compleja o continua?"}
    D -- No --> E["✅ Cloud Function<br/>o Cloud Run push"]
    D -- Sí --> F["Dataflow<br/>⚠️ el streaming cuesta 24 h al día"]
    B -- No --> G{"¿Basta con una foto<br/>periódica de los datos?"}
    G -- Sí --> H["✅ Cloud Run Job<br/>+ Cloud Scheduler → BigQuery"]
    G -- No --> C
    E --> I["✅ BigQuery<br/>tablas particionadas"]
    F --> I
    H --> I
    I --> J["✅ Looker Studio"]

El aviso económico: Dataflow en streaming mantiene trabajadores encendidos las 24 horas. Para un proyecto de portafolio eso puede ser 60-100 € al mes por un flujo que procesa doce mensajes. Pub/Sub + una función hace exactamente lo mismo por 0 € a este volumen, y demuestra igual de bien que entiendes el patrón. Reserva Dataflow para cuando la transformación lo justifique de verdad, y documenta el porqué.

La tabla de traducción que debes producir

| Componente lógico | Servicio elegido | Por qué | Alternativa descartada | Por qué se descarta |
| --- | --- | --- | --- | --- |
| Aplicación web | Cloud Run | Escala a cero, contenedor estándar, sin gestión de nodos | GKE Autopilot | El clúster cuesta desde el minuto 1 y no necesito nada de Kubernetes |
| Base de datos | ... | ... | ... | ... |

Una fila por componente. Diez a trece filas. Es el documento más citado de tu presentación final.

  1. Los tres diagramas que sirven

Un diagrama no es decoración: es una herramienta para responder una pregunta concreta. Y la razón por la que la mayoría de diagramas de arquitectura son inútiles es que intentan responder todas las preguntas a la vez y acaban siendo una maraña de cuarenta cajas.

La regla: un diagrama, un nivel de detalle, una pregunta.

Diagrama 1 — Contexto: ¿quién usa el sistema y con qué habla?

Responde a: ¿qué es esto y quién lo toca? Tu sistema es una sola caja. Alrededor, los actores y los sistemas externos.

flowchart LR
    U1["👤 Excursionista<br/>consulta y reserva"]
    U2["👤 Guarda del refugio<br/>consulta reservas del día"]
    U3["👤 Federación<br/>consulta indicadores"]
    U4["👤 Desarrollador (yo)<br/>despliega y opera"]

    S(("RefugioReserva<br/>Plataforma en GCP"))

    E1["Registrador de dominio<br/>DNS delegado"]
    E2["GitHub<br/>código fuente"]

    U1 -->|HTTPS| S
    U2 -->|HTTPS + login| S
    U3 -->|Informe compartido| S
    U4 -->|git push| E2
    E2 -->|dispara build| S
    S -.->|resuelve| E1

Diez cajas como mucho. Si tienes veinte actores, tu alcance es demasiado grande (vuelve a 08-01).

Diagrama 2 — Componentes: ¿de qué partes consta y cómo se comunican?

Responde a: ¿cómo fluye una petición y un dato por dentro? Aquí sí aparecen los servicios de GCP, pero agrupados por función, no por producto.

flowchart TB
    Usuario["👤 Usuario"]

    subgraph Borde["Borde"]
        LB["Balanceador global HTTPS<br/>+ Cloud CDN + Cloud Armor"]
    end

    subgraph Aplicacion["Aplicación"]
        RUN["Cloud Run<br/>refugio-web"]
        JOB["Cloud Run Job<br/>agregado-nocturno"]
        FN["Cloud Function<br/>procesar-evento"]
    end

    subgraph Datos["Datos operativos"]
        SQL[("Cloud SQL<br/>PostgreSQL")]
        GCS[("Cloud Storage<br/>fotos")]
        SEC["Secret Manager"]
    end

    subgraph Analitica["Analítica"]
        PS["Pub/Sub<br/>reservas-eventos"]
        BQ[("BigQuery<br/>refugio_analitica")]
        LS["Looker Studio"]
    end

    subgraph Inteligencia["IA"]
        NL["Natural Language API"]
    end

    Usuario --> LB --> RUN
    RUN --> SQL
    RUN --> GCS
    RUN --> SEC
    RUN --> PS
    PS --> FN --> BQ
    JOB --> SQL
    JOB --> BQ
    RUN --> NL
    NL --> BQ
    BQ --> LS
    LB -.->|estáticos| GCS

Las cinco reglas de un diagrama de componentes legible:

  1. Máximo 15 cajas. Si necesitas más, haz dos diagramas.
  2. Las flechas van en el sentido de la petición, no del dato. Si te lías, pon la etiqueta.
  3. Agrupa por responsabilidad (borde, aplicación, datos, analítica), no por producto.
  4. Etiqueta las flechas que no son obvias. RUN --> SQL no necesita etiqueta; LB -.-> GCS sí.
  5. Ningún cruce innecesario. Si dos líneas se cruzan, reordena las cajas.

Diagrama 3 — Despliegue: ¿dónde vive físicamente cada cosa?

Responde a: ¿qué proyecto, qué región, qué red, qué es público y qué no? Es el diagrama que un revisor de seguridad mira primero.

flowchart TB
    subgraph Internet["🌐 Internet"]
        CL["Cliente"]
    end

    subgraph Org["Organización / cuenta de facturación"]
        subgraph ProyProd["Proyecto: refugio-prod · europe-west1"]
            subgraph VPCP["VPC refugio-vpc"]
                subgraph SubP["Subred app 10.20.0.0/24"]
                    CRP["Cloud Run<br/>(conector VPC salida)"]
                end
                PSC["Acceso privado a servicios<br/>10.20.10.0/24"]
                SQLP[("Cloud SQL<br/>IP privada · sin IP pública")]
            end
            LBP["Balanceador HTTPS global<br/>IP anycast"]
            GCSP[("Buckets")]
        end
        subgraph ProyDev["Proyecto: refugio-dev · europe-west1"]
            DEV["Copia reducida<br/>sin CDN, sin dominio propio"]
        end
        subgraph ProyDatos["Proyecto: refugio-datos"]
            BQD[("BigQuery")]
        end
    end

    CL -->|HTTPS 443| LBP --> CRP
    CRP --> PSC --> SQLP
    CRP --> GCSP
    CRP -.-> BQD
    DEV -.-> BQD

Este diagrama debe dejar evidente, de un vistazo, qué está expuesto a internet. En el ejemplo: sólo el balanceador. La base de datos no tiene IP pública, Cloud Run no acepta tráfico directo (sólo del balanceador), y el proyecto de datos no es alcanzable desde fuera.

  1. Diseño de la estructura organizativa

¿Necesito una organización?

Depende de tu cuenta:

Situación Qué tienes Qué haces
Cuenta personal con Gmail Sin organización. Proyectos sueltos Los proyectos cuelgan de "Sin organización". Válido para el módulo
Cuenta con Workspace o Cloud Identity de un dominio propio Organización Crea carpetas y aprovecha para practicar 07-07
Cuenta de tu empresa Organización ajena No la uses. Crea una cuenta personal para el proyecto

Sin organización pierdes las políticas de organización y las carpetas, pero todo lo demás funciona igual y la rúbrica no exige organización. Si tienes un dominio propio (que vas a necesitar de todas formas para RNF-5), puedes crear un Cloud Identity gratuito y tener organización; es un extra que suma pero no es obligatorio.

¿Cuántos proyectos?

Un proyecto es la unidad de aislamiento, de facturación y de IAM. Tres opciones razonables:

Opción Proyectos Ventajas Inconvenientes Recomendado si
A. Uno solo miproy Sencillo, barato, rápido No demuestras separación de entornos. Un error afecta a todo Tu límite es 0 € y vas muy justo de tiempo
B. Dos (dev + prod) miproy-dev, miproy-prod El equilibrio correcto. Demuestras promoción real entre entornos Duplicas algunos recursos ✅ Por defecto
C. Cuatro o más -dev, -prod, -datos, -cicd Se parece a AlpinaShop. Separa la analítica y la entrega Más IAM que gestionar, más tiempo Si vas holgado de tiempo

La recomendación es B, con una variante barata: si tu analítica es pequeña, mete BigQuery en el proyecto de producción y ahórrate el cuarto proyecto. Lo que sí conviene separar siempre es dev de prod, porque es lo que hace creíble el pipeline de promoción de RNF-2 y porque te permite destruir dev los viernes sin miedo.

flowchart TB
    ORG["Organización (opcional)<br/>tudominio.example"]
    ORG --> P1["refugio-dev<br/>Entorno de desarrollo<br/>Destruible"]
    ORG --> P2["refugio-prod<br/>Entorno de producción<br/>Lo que se enseña"]
    ORG --> P3["refugio-datos<br/>BigQuery + Looker<br/>(opcional)"]
    ORG --> P4["refugio-cicd<br/>Artifact Registry + builds<br/>(opcional)"]

    P4 -.->|despliega en| P1
    P4 -.->|con aprobación| P2
    P1 -.->|escribe en dataset dev| P3
    P2 -.->|escribe en dataset prod| P3

La decisión de región

Una sola región. Para un proyecto en España, europe-west1 (Bélgica) o europe-southwest1 (Madrid).

Criterio europe-west1 europe-southwest1
Latencia desde España ~25-35 ms ~5-15 ms
Disponibilidad de servicios Prácticamente todos Muy buena, algún servicio llega más tarde
Precio Referencia Ligeramente superior en algunos servicios
Datos en territorio español No (Bélgica, sigue siendo UE) Sí

Escribe la decisión y su motivo. Es un ADR de tres líneas, y es la clase de detalle que demuestra que piensas en residencia del dato y no sólo en que funcione. Y recuerda de 01-05: algunos servicios son globales (IAM, Cloud DNS, el balanceador global, Artifact Registry en modo multirregión), así que la región no aplica a todo.

  1. Convención de nombres y de etiquetas

Se decide una vez, se aplica siempre, y se decide ahora porque el projectId no se cambia.

El patrón

<proyecto>-<entorno>                       para projectId
<proyecto>-<componente>[-<detalle>]        para recursos dentro del proyecto
Recurso Patrón Ejemplo bueno Ejemplo malo
Proyecto <proy>-<env> refugio-prod mi-proyecto-final-2
VPC <proy>-vpc refugio-vpc default
Subred <proy>-<uso>-<region> refugio-app-ew1 subnet-1
Servicio Cloud Run <proy>-<funcion> refugio-web service
Cloud SQL <proy>-db refugio-db instance-1
Bucket <proy>-<uso>-<sufijo> refugio-fotos-8f2a mis-fotos
Cuenta de servicio sa-<carga> sa-refugio-web service-account-1
Dataset BigQuery <proy>_<dominio> refugio_analitica dataset1
Topic Pub/Sub <entidad>-<hecho> reservas-creadas topic1
Secreto <proy>-<que> refugio-db-password password

Las reglas duras que impone GCP y que hay que conocer antes:

  • projectId: 6-30 caracteres, minúsculas, números y guiones; empieza por letra; único en todo Google Cloud y jamás reutilizable, ni siquiera tras borrar el proyecto.
  • Buckets: el nombre es único globalmente. Por eso llevan sufijo aleatorio: refugio-fotos estará cogido casi seguro. Terraform lo resuelve con random_id.
  • Cuentas de servicio: el accountId (la parte antes de la @) tiene 6-30 caracteres y tampoco se puede cambiar.
  • Nada de guiones bajos en nombres DNS-compatibles (buckets, servicios de Cloud Run). Sí en datasets y tablas de BigQuery, que usan _.
  • Nada de nombres con test, tmp, 2, nuevo, final. Todo eso acaba en producción y se queda.

Etiquetas (labels)

Las etiquetas son pares clave-valor que aparecen en la exportación de facturación. Es lo que permite responder "¿cuánto me cuesta el componente de datos?" sin adivinar. Cuestan cero y se ponen desde el primer apply.

Etiqueta Valores Para qué
proyecto refugioreserva Distinguir de otras cosas en la misma cuenta
entorno dev, prod Atribuir coste por entorno
componente web, datos, analitica, ia, red Atribuir coste por capa
gestionado-por terraform, manual Detectar lo creado a mano
caduca 2026-12-31 Recursos temporales que hay que limpiar

En Terraform se aplican de una vez con una variable común:

locals {
  etiquetas_base = {
    proyecto       = "refugioreserva"
    entorno        = var.entorno
    gestionado-por = "terraform"
  }
}

resource "google_storage_bucket" "fotos" {
  name     = "refugio-fotos-${var.sufijo}"
  location = var.region
  labels   = merge(local.etiquetas_base, { componente = "web" })
}

gestionado-por = terraform es la más útil de las cinco: cualquier recurso sin esa etiqueta, o creado a mano, salta a la vista en una consulta de facturación. Es tu detector de deriva de configuración con coste cero.

  1. Diseño de la red

Aunque uses Cloud Run —que es serverless— hay decisiones de red que tomar, porque la base de datos privada, el conector de salida y el balanceador viven en una VPC.

Plan de direccionamiento

No uses la red default. Viene con subredes en todas las regiones del mundo y reglas de firewall permisivas que no elegiste. Crea una VPC en modo personalizado.

Reserva un espacio y divídelo. Con un /16 privado tienes de sobra:

Bloque CIDR Uso Notas
Espacio del proyecto 10.20.0.0/16 Todo No se solapa con tu red doméstica (192.168.x) ni con la típica de oficina (10.0.x)
Subred de aplicación 10.20.0.0/24 VMs, GKE si lo hubiera 254 direcciones, sobran
Conector VPC de salida 10.20.8.0/28 Conector serverless Exige un /28 exacto
Acceso privado a servicios 10.20.16.0/20 Cloud SQL con IP privada Google exige un bloque reservado, mínimo /24; se recomienda /20
Reservado futuro 10.20.32.0/19 Sin usar Deja siempre espacio libre

Las dos trampas que pillan a todo el mundo la primera vez:

  1. El conector de acceso a VPC sin servidor necesita un /28 propio y sin solapar. Ni /29 ni /27: /28.
  2. Cloud SQL con IP privada necesita un rango reservado para acceso privado a servicios y un emparejamiento (peering) con la red de Google. Es un paso extra que la documentación menciona de pasada y que provoca un error críptico si falta. En Terraform son dos recursos: google_compute_global_address con purpose = "VPC_PEERING" y google_service_networking_connection.

La matriz de flujos permitidos

Este es el artefacto más valioso del diseño de red: una tabla de quién puede hablar con quién. Se escribe antes de crear una sola regla de firewall, y después se traduce a reglas casi mecánicamente.

Origen Destino Puerto Protocolo ¿Permitido? Motivo
Internet Balanceador 443 TCP ✅ Es el punto de entrada
Internet Balanceador 80 TCP ✅ Sólo para redirigir a 443
Internet Cloud Run directamente — — ❌ Debe pasar por el balanceador (--ingress=internal-and-cloud-load-balancing)
Internet Cloud SQL 5432 TCP ❌ Nunca. Sin IP pública
Balanceador Cloud Run 443 TCP ✅ NEG sin servidor
Cloud Run Cloud SQL 5432 TCP ✅ Por IP privada, vía conector
Cloud Run Cloud Storage 443 TCP ✅ API de Google
Cloud Run Secret Manager 443 TCP ✅ API de Google
Cloud Run Pub/Sub 443 TCP ✅ API de Google
Cloud Run Internet abierto — — ⚠️ Sólo si llamo a una API externa. Si no, se cierra
Cloud Function BigQuery 443 TCP ✅ API de Google
Yo (IP doméstica) Cloud SQL 5432 TCP ⚠️ Sólo por proxy autenticado, nunca IP pública
Cualquiera Cualquiera — — ❌ Denegación por defecto

La última fila es la política: todo lo que no está explícitamente permitido, se deniega. Es el principio de 03-01 y es la diferencia entre una red diseñada y una red que "funciona".

Exposición pública mínima

Escribe la lista de todo lo que va a ser alcanzable desde internet. Debería caber en tres líneas:

## Superficie pública de RefugioReserva
1. `https://refugioreserva.example` → balanceador → Cloud Run (toda la app).
2. `https://refugioreserva.example/fotos/*` → bucket vía CDN (sólo miniaturas públicas).
3. Nada más. La BD no tiene IP pública. Cloud Run no acepta tráfico directo.
   Los buckets de originales y de estado de Terraform son privados.

Si esa lista tiene más de cinco entradas, revísala: casi seguro hay algo expuesto que no hace falta.

  1. Diseño de la identidad

Igual que la red: se escribe la tabla antes de crear nada. Y se aplica el principio de 03-04 en su versión más práctica: una cuenta de servicio por carga de trabajo, con los roles mínimos, y ninguna clave descargada.

Los tres tipos de identidad de tu proyecto

Tipo Quién es Cómo se autentica
Humanos Tú, y quien revise tu proyecto Tu cuenta de Google, con 2FA
Cargas de trabajo Cloud Run, funciones, jobs Cuenta de servicio adjunta, sin clave
CI/CD externo GitHub Actions o Cloud Build Workload Identity Federation, sin clave

La tabla de identidades

Identidad Tipo Roles Sobre qué recurso Por qué exactamente esto
[email protected] Humano roles/owner Proyectos Eres el administrador. Es el único owner aceptable
sa-refugio-web Cloud Run (app) roles/cloudsql.client Proyecto Conectar a la BD, no administrarla
roles/secretmanager.secretAccessor Sólo los 2 secretos que usa Leer, no listar ni crear
roles/storage.objectAdmin Sólo el bucket de fotos Subir y leer fotos
roles/pubsub.publisher Sólo el topic de eventos Publicar, no suscribirse
roles/logging.logWriter Proyecto Escribir logs
roles/cloudtrace.agent Proyecto Enviar trazas
sa-procesar-evento Cloud Function roles/bigquery.dataEditor Sólo el dataset analítico Insertar filas
roles/language.user (según API) Proyecto Llamar a la API de NL
sa-job-nocturno Cloud Run Job roles/cloudsql.client Proyecto Leer la BD
roles/bigquery.jobUser + dataEditor Dataset Cargar agregados
sa-deploy CI/CD (WIF) roles/run.developer Proyecto Desplegar revisiones
roles/artifactregistry.writer Repositorio Publicar imágenes
roles/iam.serviceAccountUser Sólo sobre sa-refugio-web Poder adjuntar esa SA al servicio

Los cinco principios que hay que respetar y que la rúbrica comprueba:

  1. Nunca roles/editor ni roles/owner en una cuenta de servicio. Son los roles primitivos de 03-04 y conceden miles de permisos.
  2. El ámbito más estrecho posible. secretAccessor sobre el secreto, no sobre el proyecto. En Terraform es google_secret_manager_secret_iam_member, no google_project_iam_member.
  3. Una SA por carga de trabajo. Si la función y la app comparten SA, comparten permisos, y el radio de explosión de un fallo se duplica.
  4. Cero claves JSON. Las cargas dentro de GCP usan la SA adjunta; el CI/CD externo usa WIF. Si tienes un .json, has fallado.
  5. serviceAccountUser es el permiso que se olvida. Para que sa-deploy pueda desplegar un servicio que corre como sa-refugio-web, necesita actuar como esa cuenta. Es el error 403 más frecuente del primer despliegue automatizado.

Y el que se descubre tarde: la cuenta de servicio por defecto de Compute Engine tiene rol editor. Si dejas que tus recursos la usen, todo tu diseño de mínimo privilegio es decorativo. Crea SA explícitas para todo.

  1. Modelo de datos y ciclo de vida del dato

Qué se guarda dónde y por qué

La tabla que evita el error más caro de estos proyectos, que es meterlo todo en la base de datos operativa:

Dato Dónde vive Por qué ahí Qué NO va aquí
Estado del negocio (reservas, usuarios, catálogo) Cloud SQL Necesita transacciones e integridad Histórico de eventos, ficheros
Ficheros binarios (imágenes, PDF) Cloud Storage Barato, servible por CDN, no infla la BD Nada estructurado que necesites consultar
Eventos de negocio (histórico inmutable) BigQuery Analítica, agregación, coste por consulta Datos que necesitas leer en <100 ms
Sesiones y estado efímero Firestore o memoria Acceso por clave, TTL Nada que deba sobrevivir
Contraseñas, claves, cadenas de conexión Secret Manager Cifrado, versionado, auditado Jamás en variables de entorno en claro ni en el repo
Configuración no sensible Variables de entorno del servicio Cambia sin reconstruir la imagen Secretos
Estado de Terraform Bucket dedicado con versionado Bloqueo y recuperación Cualquier otra cosa

El esquema operativo

Escríbelo como DDL, aunque sea un borrador. Es lo que te obliga a pensar en claves, restricciones y tipos:

-- Esquema operativo de RefugioReserva (Cloud SQL PostgreSQL)
-- Todos los datos son FICTICIOS.

CREATE TABLE refugio (
    id            SERIAL PRIMARY KEY,
    nombre        TEXT        NOT NULL UNIQUE,
    altitud_m     INTEGER     NOT NULL CHECK (altitud_m BETWEEN 500 AND 3500),
    capacidad     INTEGER     NOT NULL CHECK (capacidad > 0),
    activo        BOOLEAN     NOT NULL DEFAULT TRUE,
    creado_en     TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE reserva (
    id            UUID        PRIMARY KEY DEFAULT gen_random_uuid(),
    refugio_id    INTEGER     NOT NULL REFERENCES refugio(id),
    fecha         DATE        NOT NULL,
    plazas        INTEGER     NOT NULL CHECK (plazas BETWEEN 1 AND 12),
    -- Datos de contacto: FICTICIOS. Ver política de retención más abajo.
    nombre_titular TEXT       NOT NULL,
    email_titular  TEXT       NOT NULL,
    estado        TEXT        NOT NULL DEFAULT 'confirmada'
                              CHECK (estado IN ('confirmada','cancelada')),
    creada_en     TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Índice que sostiene la consulta más frecuente: disponibilidad por refugio y fecha
CREATE INDEX idx_reserva_refugio_fecha ON reserva (refugio_id, fecha)
    WHERE estado = 'confirmada';

CREATE TABLE opinion (
    id            SERIAL PRIMARY KEY,
    refugio_id    INTEGER     NOT NULL REFERENCES refugio(id),
    texto         TEXT        NOT NULL,
    puntuacion    INTEGER     CHECK (puntuacion BETWEEN 1 AND 5),
    -- Rellenados por la API de Natural Language
    sentimiento   NUMERIC(4,3),
    magnitud      NUMERIC(4,3),
    creada_en     TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

Tres detalles que merecen atención y que puntúan en la rúbrica:

  • El CHECK en plazas es una regla de negocio expresada en la base de datos. Es gratis y evita datos imposibles aunque la aplicación tenga un bug.
  • El índice parcial (WHERE estado = 'confirmada') es más pequeño y más rápido que uno completo, porque las reservas canceladas no participan en el cálculo de disponibilidad.
  • La comprobación de capacidad no está en el esquema. No se puede: depende de la suma de reservas de una fecha. Va en una transacción con bloqueo en la aplicación, y es precisamente lo que probará la prueba de integración obligatoria.

El esquema analítico

En BigQuery el criterio es distinto: se desnormaliza, se particiona por fecha y se agrupa (cluster) por lo que más se filtra. La razón es económica: BigQuery cobra por bytes leídos, y una tabla sin particionar se lee entera cada vez.

-- Almacén analítico. Particionada por día y agrupada por refugio.
CREATE TABLE `refugio-datos.refugio_analitica.reservas_eventos` (
  evento_id       STRING    NOT NULL,
  ocurrido_en     TIMESTAMP NOT NULL,
  tipo_evento     STRING    NOT NULL,   -- creada | cancelada
  reserva_id      STRING    NOT NULL,
  refugio_id      INT64     NOT NULL,
  refugio_nombre  STRING,               -- desnormalizado a propósito
  fecha_estancia  DATE      NOT NULL,
  plazas          INT64     NOT NULL,
  -- SIN datos de contacto: no se replican al almacén analítico
)
PARTITION BY DATE(ocurrido_en)
CLUSTER BY refugio_id
OPTIONS (
  partition_expiration_days = 1095,      -- 3 años y se borra solo
  require_partition_filter  = TRUE       -- obliga a filtrar por fecha
);

require_partition_filter = TRUE es la opción que te salva la factura. Con ella, una consulta sin WHERE DATE(ocurrido_en) ... falla en vez de escanear la tabla entera. Es el equivalente a un cinturón de seguridad y en un proyecto con límite de coste no es opcional.

Fíjate también en lo que no está: los datos de contacto no viajan al almacén analítico. Nadie necesita el correo del titular para calcular la ocupación, y todo dato personal que no replicas es un problema de RGPD que no tienes.

El ciclo de vida del dato

Cada dato nace, vive y debe morir. La última parte es la que nunca se diseña.

Dato Nace Vive Muere Mecanismo
Reserva Al reservar En Cloud SQL 24 meses tras la estancia Job nocturno que anonimiza contacto
Datos de contacto Con la reserva En Cloud SQL 6 meses tras la estancia UPDATE que sustituye por anonimizado
Foto original Al subirla Bucket Standard Nunca (son del refugio) —
Miniatura Generada Bucket + CDN Se regenera si se pierde Derivada, no crítica
Evento analítico Al reservar BigQuery 3 años partition_expiration_days
Log de aplicación Cada petición Cloud Logging 30 días Retención del bucket de logs
Backup de Cloud SQL Diario 7 días Automático Retención de backups
Imagen de contenedor Cada build Artifact Registry 10 versiones Política de limpieza

⚠️ Advertencia de RGPD, y no es un formalismo. En cuanto tu sistema almacena un nombre, un correo, un teléfono o una posición asociada a una persona identificable, estás tratando datos personales, aunque sean inventados y aunque sea un proyecto de aprendizaje.

Para este proyecto: usa exclusivamente datos ficticios (nombres generados, correos @example.com, teléfonos del rango reservado para ficción). Con eso, formalmente no hay tratamiento de datos personales y no hay obligación.

Pero diseña como si la hubiera, porque el hábito es lo que se evalúa y lo que se transfiere a un trabajo real: minimización (no guardes lo que no usas), limitación de la finalidad (no repliques el contacto al almacén analítico), plazo de conservación definido con borrado real y automático, cifrado en reposo, acceso restringido y trazabilidad de quién accede.

Y si alguna vez este diseño fuese a tratar datos reales de personas, haría falta una revisión de RGPD y de compliance completa —base jurídica, registro de actividades, evaluación de impacto si procede, contrato de encargo del tratamiento con Google— que queda por completo fuera del alcance de este curso.

  1. Estimación de coste previa

Se hace ahora, con el diseño en la mano y antes de construir. Si no cabe en el límite de 08-01, el que cambia es el diseño, no el límite.

Método en cinco pasos

  1. Lista los servicios de tu tabla de traducción.
  2. Para cada uno, estima el dimensionador que determina el precio: horas encendido, GB almacenados, GB procesados, número de peticiones, GB de salida a internet.
  3. Mira si el nivel gratuito lo cubre. Sorprendentemente a menudo, sí.
  4. Usa la calculadora oficial para lo que no cubra.
  5. Súmalo y añade un 25 % de margen para lo que no has previsto.

Los dimensionadores que importan

Servicio Qué se paga Cómo lo estimas Trampa habitual
Cloud Run vCPU-s + GiB-s + peticiones Peticiones/mes × duración media min-instances > 0 factura 24 h al día
Cloud SQL Instancia encendida, por hora 730 h × precio/h Se paga aunque no la uses
Cloud Storage GB/mes + operaciones + salida GB estimados La salida a internet es lo caro, no el almacenamiento
BigQuery Bytes leídos + GB almacenados Consultas/día × bytes por consulta Un panel que se refresca solo escanea sin parar
Pub/Sub GiB publicados Mensajes × tamaño Volumen despreciable en este proyecto
Cloud Functions Invocaciones + GB-s Invocaciones/mes Idem
Balanceador HTTP(S) Regla de reenvío por hora + tráfico 730 h × precio Cuesta aunque no reciba tráfico
Cloud Logging GB ingeridos por encima del gratuito Volumen de logs Logs de depuración en producción
Artifact Registry GB almacenados Imágenes × tamaño Nadie borra imágenes viejas
APIs de IA Por unidad procesada Documentos/imágenes al mes Reprocesar en cada carga de página

Los cuatro sumideros de dinero de un proyecto de portafolio, por orden de frecuencia:

  1. Cloud SQL encendida 24/7. Es casi siempre la partida mayor.
  2. El balanceador global. La regla de reenvío cuesta por hora exista o no tráfico. Puede ser 15-20 €/mes. Si tu límite es muy ajustado, plantéate servir Cloud Run con su propio dominio personalizado (que da TLS gratis) y documentar en un ADR que renuncias a CDN y Cloud Armor por coste.
  3. GKE estándar. Un clúster de tres nodos ronda los 100 €/mes. No lo uses.
  4. Dataflow en streaming. Trabajadores encendidos permanentemente.

La tabla de estimación

| Servicio | Configuración | Dimensionador estimado | Nivel gratuito | Coste/mes |
| --- | --- | --- | --- | --- |
| Cloud Run web | 1 vCPU / 512 MiB / min=0 | 20.000 pet., 200 ms | Sí, cubre casi todo | ~0,20 € |
| Cloud SQL | db-f1-micro, 10 GB HDD | 730 h | No | ~8,00 € |
| ... | | | | |
| **Subtotal** | | | | **X €** |
| **+25 % margen** | | | | **Y €** |
| **Límite fijado (08-01)** | | | | **12 €** |
| **¿Cabe?** | | | | ✅ / ❌ |

Qué hacer si no cabe

En este orden, del cambio más barato al más doloroso:

# Medida Ahorro típico Coste para el proyecto
1 Apagar el entorno de desarrollo cuando no se usa (destroy/apply) 40-50 % del total Ninguno, si tu IaC funciona
2 Bajar Cloud SQL a la instancia más pequeña y sin HA 50-70 % de esa partida Ninguno en un portafolio
3 Programar parada nocturna de Cloud SQL (9:00-23:00) ~40 % adicional La demo no va de madrugada
4 Reducir retención de logs a 7 días Pequeño Menos histórico para diagnosticar
5 Quitar CDN y balanceador; usar dominio personalizado de Cloud Run 15-20 €/mes Pierdes Cloud Armor y caché. Requiere ADR
6 Cambiar Cloud SQL por Firestore Toda la partida Rediseño de la capa de datos. Requiere ADR
7 Reducir alcance funcional Variable Última opción

Y una decisión que hay que tomar conscientemente: si tu límite es 0 €, la arquitectura correcta es Firestore + Cloud Run + BigQuery + Cloud Functions + dominio personalizado de Cloud Run, sin balanceador y sin Cloud SQL. Es un diseño perfectamente defendible, siempre que esté escrito por qué. Un proyecto que dice "elegí Firestore porque mi restricción de coste era 0 € y Cloud SQL cuesta 8 €/mes encendida" demuestra más criterio que uno que gastó 60 € sin pensarlo.

  1. Definición de los SLO del proyecto

De 07-06, en su versión mínima viable. Uno o dos SLO bastan. El error es definir seis y no medir ninguno.

El proceso en cuatro pasos

Paso 1 — ¿Cuál es el viaje crítico del usuario? No "que la web funcione". Algo concreto: "un excursionista consulta disponibilidad y completa una reserva".

Paso 2 — ¿Qué SLI lo mide? Un SLI es un cociente de eventos buenos entre eventos válidos:

Tipo de SLI Fórmula Cuándo usarlo
Disponibilidad peticiones con código < 500 ÷ peticiones totales Siempre. Es el básico
Latencia peticiones < umbral ÷ peticiones totales Si la percepción importa
Corrección operaciones correctas ÷ operaciones intentadas Para flujos con dinero o estado
Frescura datos con retraso < X ÷ total Para pipelines de datos

Paso 3 — Fija el objetivo. Sé realista: el objetivo debe ser alcanzable con tu arquitectura y superior a lo que un usuario nota. 99,9 % mensual es un buen punto de partida; 99,99 % en un proyecto de portafolio con una sola región es mentira, porque la propia región no lo garantiza.

Paso 4 — Calcula el presupuesto de error. Es lo que hace útil al SLO:

SLO Error permitido/mes En tiempo (30 días)
99 % 1 % 7 h 12 min
99,5 % 0,5 % 3 h 36 min
99,9 % 0,1 % 43 min 12 s
99,95 % 0,05 % 21 min 36 s
99,99 % 0,01 % 4 min 19 s

La tabla de SLO del proyecto

# Viaje crítico SLI Objetivo Ventana Presupuesto de error Fuente de la medida
SLO-1 Consultar disponibilidad % de peticiones a /api/disponibilidad con código < 500 99,5 % 30 días 3 h 36 min Métrica run.googleapis.com/request_count
SLO-2 Completar una reserva % de POST /api/reservas con latencia < 1.500 ms 95 % 30 días 36 h de peticiones lentas Distribución request_latencies

Y la política de presupuesto de error, escrita ahora, que es lo que convierte el SLO en una herramienta y no en un número decorativo:

## Política de presupuesto de error (RefugioReserva)
- **Presupuesto > 50 % restante:** desarrollo normal. Se despliega cuando se quiera.
- **Presupuesto < 50 %:** cada despliegue en producción exige que la prueba
  de extremo a extremo haya pasado en dev.
- **Presupuesto < 10 %:** se congela la funcionalidad nueva. Sólo correcciones
  de fiabilidad hasta que se recupere.
- **Presupuesto agotado:** se escribe un post-mortem breve en `docs/diario.md`
  antes de volver a desplegar nada.

En un proyecto de una persona esto puede sonar excesivo. No lo es: es un párrafo, y es exactamente el tipo de artefacto que en una entrevista demuestra que has entendido para qué sirve un SLO.

  1. Decisiones de arquitectura documentadas (ADR)

Un ADR (Architecture Decision Record) es una página que registra una decisión importante. Es el documento más valioso que vas a escribir en este proyecto, y aquí está el porqué, sin adornos:

  • Dentro de tres meses no te acordarás de por qué elegiste Firestore. El código dice qué hiciste; el ADR dice por qué.
  • En una entrevista te van a preguntar exactamente eso. Un ADR es una respuesta preparada.
  • Escribir la decisión te obliga a tenerla. La mitad de las veces, al llegar a la sección "alternativas" descubres que no habías considerado ninguna.
  • Permite revisar la decisión con honestidad. Si el contexto cambia, se escribe un ADR nuevo que supersede al anterior. No se reescribe el viejo: se deja como registro histórico. Así se ve la evolución del criterio, que es lo que se evalúa.

La plantilla

# ADR-00X: [Título en forma de decisión, no de pregunta]

- **Fecha:** 2026-09-12
- **Estado:** Propuesta | **Aceptada** | Reemplazada por ADR-00Y | Obsoleta

## Contexto
¿Qué situación obliga a decidir? ¿Qué restricciones hay (coste, tiempo,
conocimiento, requisitos)? Hechos, no opiniones. 5-10 líneas.

## Opciones consideradas
### Opción A — <nombre>
- Ventajas:
- Inconvenientes:
- Coste estimado:

### Opción B — <nombre>
- Ventajas:
- Inconvenientes:
- Coste estimado:

## Decisión
Elegimos **<opción>**.
Porque <el criterio que decidió>. El factor determinante fue <uno solo>.

## Consecuencias
### Positivas
-
### Negativas (lo que aceptamos perder)
-
### Qué haría cambiar esta decisión
Si ocurre <X>, habría que revisarla.

Las dos secciones que la gente deja flojas y que son las que valen:

  • "Negativas": toda decisión de arquitectura pierde algo. Si tu ADR no tiene inconvenientes, no has decidido: has justificado lo que ya querías hacer. Escribir "acepto que sin balanceador pierdo Cloud Armor y caché de borde" demuestra criterio, no debilidad.
  • "Qué haría cambiar esta decisión": convierte la decisión en revisable y demuestra que sabes que es contextual. Es exactamente lo que hizo AlpinaShop con DA-004 sobre Anthos.

Los ADR que necesitas como mínimo

ADR Decisión Por qué es importante
ADR-001 Servicio de cómputo Es la decisión estructural de la aplicación
ADR-002 Base de datos Es la más cara de revertir
ADR-003 Estrategia de datos (streaming vs. lotes) Determina complejidad y coste
ADR-004 Enfoque del componente de IA API preentrenada vs. modelo propio
ADR-005 Estructura de proyectos y región Irreversible
ADR-006 (frecuente) Recortes por coste El más honesto y el que más impresiona

Tres son el mínimo de la rúbrica; cinco o seis es lo normal. Uno por sesión de diseño y ya los tienes.

  1. Revisión del diseño antes de implementar

Este es el hito M1 de 08-01. Se pasa o no se pasa; no hay "casi". Repásala tú mismo, en frío, preferiblemente al día siguiente de terminar el diseño.

Lista de verificación del diseño

Arquitectura

  • [ ] Los seis requisitos funcionales tienen un servicio asignado
  • [ ] Los ocho requisitos no funcionales tienen un mecanismo asignado
  • [ ] Cada servicio tiene su justificación y su alternativa descartada escritas
  • [ ] Existen los tres diagramas y son coherentes entre sí
  • [ ] Ningún diagrama tiene más de 15 cajas

Organización y nombres

  • [ ] Está decidido cuántos proyectos y cómo se llaman exactamente
  • [ ] Los projectId cumplen las reglas (6-30, minúsculas, sin test/final/2)
  • [ ] Está decidida la región y está escrito el motivo
  • [ ] Hay convención de nombres para todos los tipos de recurso
  • [ ] Hay convención de etiquetas, incluida gestionado-por

Red

  • [ ] Hay plan de direccionamiento sin solapamientos
  • [ ] El conector serverless tiene su /28
  • [ ] Cloud SQL privada tiene su rango de acceso privado a servicios
  • [ ] La matriz de flujos está escrita, con denegación por defecto
  • [ ] La superficie pública cabe en cinco líneas

Identidad

  • [ ] Hay una cuenta de servicio por carga de trabajo
  • [ ] Ninguna tiene owner ni editor
  • [ ] Cada rol está en el ámbito más estrecho posible
  • [ ] Está previsto WIF para el CI/CD, sin claves JSON
  • [ ] Está contemplado serviceAccountUser para el desplegador

Datos

  • [ ] Está claro qué dato vive dónde y por qué
  • [ ] El esquema operativo está escrito como DDL
  • [ ] La tabla analítica está particionada, con require_partition_filter
  • [ ] Está definido el ciclo de vida de cada dato, incluida su eliminación
  • [ ] Ningún dato de contacto se replica al almacén analítico
  • [ ] Está anotado que todos los datos son ficticios

Coste

  • [ ] Hay tabla de estimación por servicio
  • [ ] El total con 25 % de margen cabe en el límite de 08-01
  • [ ] Si no cabía, hay un ADR que documenta el recorte
  • [ ] El presupuesto con alertas ya está creado

Operación

  • [ ] Hay al menos un SLI y un SLO con su ventana
  • [ ] El presupuesto de error está calculado
  • [ ] Hay política de presupuesto de error escrita
  • [ ] Está previsto qué se va a monitorizar

Documentación

  • [ ] Existen ≥3 ADR con contexto, opciones, decisión y consecuencias
  • [ ] docs/arquitectura.md está escrito y contiene los diagramas
  • [ ] El diario.md tiene entradas de todas las sesiones de diseño

Las cinco preguntas de control

Si tienes todas las casillas y aún así no puedes responder a estas cinco sin mirar, el diseño no está terminado:

  1. ¿Cuánto costará al mes y cuál es la partida mayor?
  2. Si se cae la base de datos, ¿qué deja de funcionar y qué sigue funcionando?
  3. ¿Quién —qué identidad exactamente— puede leer los datos de los usuarios?
  4. ¿Qué descartaste en la decisión más importante y por qué?
  5. ¿Cómo te enterarás de que algo va mal antes de que te lo diga alguien?

  1. El diseño completo de RefugioReserva

Como referencia consolidada, así queda el diseño del proyecto de ejemplo. Léelo como un modelo de formato y nivel de detalle, no como algo a copiar.

Tabla de traducción

Componente lógico Servicio Por qué Descartado Por qué se descarta
Punto de entrada Balanceador HTTPS global + CDN + Cloud Armor Certificado gestionado, caché de fotos, WAF básico Dominio personalizado de Cloud Run Más barato, pero sin CDN ni WAF. Cabe en presupuesto, así que se mantiene el balanceador
Aplicación Cloud Run refugio-web Escala a cero (tráfico casi nulo), contenedor estándar GKE Autopilot Coste desde el minuto 1, no necesito nada de Kubernetes
App Engine estándar Menos portable, el contenedor lo quiero por RF-1
Trabajo programado Cloud Run Job + Scheduler Reutiliza la misma imagen Cloud Composer Desproporcionado: un DAG para una tarea
Objetos Cloud Storage refugio-fotos Barato, integrado con CDN Guardar en la BD Infla la BD y encarece los backups
BD operativa Cloud SQL PostgreSQL db-f1-micro Integridad de la capacidad, transacción con bloqueo Firestore Sin transacciones multi-documento cómodas para el control de aforo. Coste: +8 €/mes, aceptado
Eventos Pub/Sub reservas-eventos Desacopla la web de la analítica Escribir en BigQuery desde la web Acopla la latencia del usuario a BigQuery
Procesamiento Cloud Function procesar-evento Volumen mínimo, coste cero Dataflow streaming ~70 €/mes para 60 mensajes al día
Almacén analítico BigQuery refugio_analitica Nivel gratuito suficiente, SQL Consultar la réplica de Cloud SQL Mezcla carga analítica y operativa
Visualización Looker Studio Gratis, conector nativo Grafana Habría que alojarlo y pagarlo
IA Natural Language API (sentimiento) Funciona el primer día, sin entrenar AutoML de texto Días de trabajo y coste de entrenamiento para el mismo requisito
Identidad 4 cuentas de servicio + WIF Mínimo privilegio, sin claves Una SA para todo Radio de explosión, y suspende el bloque D
Secretos Secret Manager Versionado y auditado Variables de entorno Quedan visibles en la consola y en el describe
Observabilidad Cloud Monitoring + Logging + un SLO Nativo, sin coste a este volumen Prometheus autogestionado Coste y tiempo
Entrega Cloud Build desde GitHub WIF nativo con GCP GitHub Actions Equivalente; se elige Cloud Build por integración con Artifact Registry
IaC Terraform, backend GCS Estándar del sector, portable Deployment Manager En retirada desde 2025 (ver 06-05)

Estructura y nombres

Elemento Valor
Proyectos refugio-dev, refugio-prod, refugio-datos
Región europe-west1 (Bélgica). Motivo: catálogo completo de servicios y precio de referencia; la latencia extra de 20 ms es irrelevante para este caso de uso
VPC refugio-vpc (personalizada, por proyecto)
Espacio IP dev 10.10.0.0/16 · prod 10.20.0.0/16
Etiquetas proyecto=refugioreserva, entorno, componente, gestionado-por
Dominio refugioreserva.example (prod), dev.refugioreserva.example (dev)

Coste estimado

Servicio Configuración Coste/mes
Cloud Run (prod + dev) 1 vCPU, 512 MiB, min=0 ~0,30 €
Cloud SQL prod db-f1-micro, 10 GB HDD, sin HA ~8,00 €
Cloud SQL dev Se crea y destruye por sesión (~20 h/mes) ~0,25 €
Cloud Storage 2 GB Standard + ciclo de vida ~0,10 €
BigQuery <1 GB, <5 GB consultados 0,00 €
Pub/Sub + Functions ~2.000 eventos/mes 0,00 €
Balanceador HTTPS 1 regla de reenvío ~18,00 € ❌
Artifact Registry 2 GB con limpieza a 10 versiones ~0,20 €
NL API 400 documentos, una sola vez ~0,40 €
Subtotal 27,25 €
+25 % margen 34,06 €
Límite (08-01) 12,00 €
¿Cabe? ❌ No

No cabe. El balanceador se come más que todo lo demás junto. Esto no es un fallo del diseño: es exactamente para lo que sirve estimar antes de construir. Y la respuesta va en un ADR:

# ADR-006: Renunciar al balanceador global y usar el dominio personalizado de Cloud Run

- **Fecha:** 2026-09-13
- **Estado:** Aceptada

## Contexto
El diseño inicial usa un balanceador HTTPS global con Cloud CDN y Cloud Armor.
La estimación de coste da 34 €/mes frente a un límite autoimpuesto de 12 €.
El balanceador solo son ~18 €/mes, y los cobra por existir, no por tráfico.
El tráfico real esperado del proyecto es de decenas de peticiones al día.

## Opciones consideradas
### A. Mantener el balanceador y subir el límite a 40 €/mes
- Ventajas: arquitectura completa, CDN y WAF, práctica con 03-02/03-03/03-05.
- Inconvenientes: 3,3 veces el límite. Anula el ejercicio de la restricción.

### B. Dominio personalizado de Cloud Run (TLS gestionado incluido)
- Ventajas: 0 €. TLS válido. Cumple RNF-5.
- Inconvenientes: sin Cloud CDN, sin Cloud Armor, sin reparto de tráfico
  entre backends heterogéneos.

### C. Balanceador solo durante una semana, para demostrarlo, y luego destruirlo
- Ventajas: coste ~4 €. Demuestro que sé montarlo, con capturas y con el
  Terraform escrito.
- Inconvenientes: la arquitectura final no lo tiene; hay que explicarlo.

## Decisión
Elegimos **C**. El módulo `infra/modules/balanceador/` queda escrito y probado;
se despliega durante la semana de pruebas de carga (08-04), se documenta con
capturas y medidas de caché, y después se destruye. El estado permanente
del proyecto usa el dominio personalizado de Cloud Run.

El factor determinante: la restricción de coste es un requisito del proyecto,
no un obstáculo, y saltármela sería suspender el propio ejercicio.

## Consecuencias
### Positivas
- Coste estable de ~9 €/mes, dentro del límite, con margen.
- El código del balanceador existe y está probado: el conocimiento queda.
- Da material para la presentación: una decisión de coste real y medida.

### Negativas
- La arquitectura permanente no tiene WAF. Se mitiga parcialmente con
  límites de concurrencia en Cloud Run y validación de entrada en la app.
- Sin CDN, las fotos se sirven desde el bucket con URL firmadas; peor
  latencia, irrelevante a este volumen.

## Qué haría cambiar esta decisión
Si el proyecto recibiese tráfico real (>10.000 visitas/mes) o si el límite
subiera por encima de 30 €/mes, se redesplegaría el balanceador: el módulo
de Terraform ya está escrito y sería un `apply`.

Coste revisado: 9,55 €/mes, dentro del límite. Y, sobre todo: una historia que contar en la presentación final que vale más que el balanceador.

SLO

# SLI Objetivo Ventana Presupuesto de error
SLO-1 % de peticiones a /api/* con código < 500 99,5 % 30 días 3 h 36 min
SLO-2 % de POST /api/reservas con latencia < 1.500 ms 95 % 30 días —

Errores Comunes y Consejos

Diseñar la arquitectura como una lista de productos que quieres usar. El síntoma es un diagrama con doce logos de GCP y ninguna justificación. La cura es el paso de los componentes lógicos: primero qué hace falta, después con qué se implementa.

Saltarse la columna "alternativa descartada". Es la mitad de los 20 puntos del bloque A. Y es la pregunta literal de una entrevista.

Crear los proyectos con nombres provisionales. No hay nombres provisionales en GCP: el projectId es para siempre y no se puede reutilizar ni tras borrarlo.

Usar la VPC default. Trae subredes en todas las regiones y reglas permisivas que no elegiste. Crear una VPC personalizada cuesta cinco líneas de Terraform.

Olvidar el rango de acceso privado a servicios. Cloud SQL con IP privada necesita un bloque reservado y un peering. Si no está en el diseño, aparece como un error incomprensible el día que creas la base de datos.

No particionar las tablas de BigQuery. Es el error que se paga en la factura, no en el rendimiento. Y require_partition_filter = TRUE es tu red de seguridad.

Definir seis SLO. Uno bien medido vale más que seis en un documento. Empieza por disponibilidad.

Diseñar el ciclo de vida sin la eliminación. "Se guarda para siempre" no es una política de retención: es la ausencia de una. Y en cuanto haya datos personales de verdad, es un incumplimiento.

Consejo: escribe el ADR el día que tomas la decisión, no al final. Quince minutos entonces, o una reconstrucción inventada tres semanas después.

Consejo: dibuja los diagramas en mermaid dentro del repositorio, no en una herramienta externa. Versionan con el código, se actualizan en el mismo commit que el cambio y se ven en GitHub. Un diagrama en un PNG exportado de una herramienta web está desactualizado desde el segundo día.

Consejo: haz la estimación de coste aunque estés seguro de que cabe. El caso de RefugioReserva —donde el balanceador se comía el triple del presupuesto— es lo normal, no la excepción. Ese descubrimiento vale más que el propio diseño.

Consejo: si dudas entre dos servicios más de veinte minutos, elige el más simple y escribe el ADR. La decisión reversible tomada rápido es mejor que la decisión perfecta tomada tarde. Y el ADR ya te deja la puerta abierta.

Ejercicios

Ejercicio 1 — Traduce tus requisitos a arquitectura y dibújala

Produce, para tu proyecto: la lista de componentes lógicos con qué hace cada uno en tu dominio; la tabla de traducción completa con las cuatro columnas obligatorias (servicio, por qué, alternativa descartada, por qué se descarta); y los tres diagramas en mermaid —contexto, componentes y despliegue— respetando el máximo de 15 cajas y las cinco reglas de legibilidad.

Guárdalo todo en docs/arquitectura.md.

Ejercicio 2 — Diseña red, identidad y datos sobre papel

Sin crear nada en GCP, produce: el plan de direccionamiento con sus bloques (incluidos el /28 del conector y el rango de acceso privado a servicios); la matriz de flujos permitidos con la fila de denegación por defecto; la lista de superficie pública; la tabla de identidades con una cuenta de servicio por carga y sus roles en el ámbito más estrecho; el DDL del esquema operativo; el esquema de la tabla analítica particionada; y la tabla de ciclo de vida de cada dato con su mecanismo de eliminación.

Añade la nota explícita de que todos los datos son ficticios y qué harías distinto si no lo fueran.

Ejercicio 3 — Estima el coste, define los SLO y escribe los ADR

Rellena la tabla de estimación de coste con la calculadora oficial y compárala con tu límite. Si no cabe, aplica las medidas por orden y escribe el ADR del recorte. Define uno o dos SLO con su SLI, objetivo, ventana y presupuesto de error, más la política de presupuesto de error. Escribe al menos tres ADR con la plantilla completa, incluidas las secciones de consecuencias negativas y de qué haría cambiar la decisión.

Cierra con la lista de verificación de la sección 13 completa y responde por escrito a las cinco preguntas de control.

Soluciones

Solución 1 — Arquitectura de RefugioReserva

Componentes lógicos rellenados:

Componente lógico Qué hace en RefugioReserva
Punto de entrada Sirve refugioreserva.example por HTTPS con certificado válido
Aplicación web Busca disponibilidad, crea reservas, muestra el panel del guarda
Trabajos asíncronos Job nocturno que agrega ocupación diaria a BigQuery y anonimiza contactos caducados
Objetos Fotos de los refugios: original y miniatura
BD operativa Refugios, reservas, opiniones, usuarios
Transporte de eventos Cada reserva creada o cancelada emite un evento
Almacén analítico Histórico de eventos y agregados de ocupación
Visualización Panel de la federación: ocupación, cancelaciones, sentimiento
IA Puntuación de sentimiento de las opiniones
Identidad y secretos 4 SA, contraseña de BD y clave de sesión en Secret Manager
Observabilidad Panel de las 4 señales, 2 alertas, SLO de disponibilidad
Entrega continua Cloud Build desde GitHub con WIF
IaC Terraform con módulos, estado en GCS

La tabla de traducción y los tres diagramas son los de la sección 14 y las secciones 4. Un detalle del diagrama de despliegue que conviene señalar: tras el ADR-006, el balanceador desaparece del estado permanente y Cloud Run se expone con su dominio personalizado, de modo que el diagrama de despliegue definitivo tiene una caja menos y la flecha Cliente → Cloud Run va directa. El diagrama se actualiza cuando cambia la decisión; un diagrama que contradice al ADR es peor que no tener diagrama.

Solución 2 — Red, identidad y datos de RefugioReserva

Direccionamiento (prod):

Bloque CIDR Uso
Espacio de prod 10.20.0.0/16 Reservado entero
Subred de aplicación 10.20.0.0/24 Reservada; hoy sin VMs
Conector serverless 10.20.8.0/28 Salida de Cloud Run hacia la VPC
Acceso privado a servicios 10.20.16.0/20 Peering para Cloud SQL
Libre 10.20.32.0/19 Futuro

Dev usa 10.10.0.0/16 con la misma estructura. No se solapan a propósito: si algún día quisiera emparejar las dos VPC, podría; si se solaparan, no.

Matriz de flujos: la de la sección 7, con dos precisiones tras el ADR-006. Como ya no hay balanceador, Cloud Run se configura con --ingress=all (necesario para el dominio personalizado) y la protección se traslada a: autenticación en las rutas privadas, validación estricta de entrada, y --max-instances=5 como tope de gasto y de abuso. Esta pérdida está reconocida en el ADR-006 y aparecerá también en la autoevaluación de 08-05 como deuda técnica consciente.

Identidades:

Identidad Rol Ámbito
sa-refugio-web roles/cloudsql.client proyecto
roles/secretmanager.secretAccessor secretos refugio-db-password, refugio-session-key
roles/storage.objectAdmin bucket refugio-fotos-8f2a
roles/pubsub.publisher topic reservas-eventos
roles/logging.logWriter, roles/cloudtrace.agent proyecto
sa-procesar-evento roles/bigquery.dataEditor dataset refugio_analitica
roles/pubsub.subscriber suscripción reservas-eventos-sub
sa-job-nocturno roles/cloudsql.client proyecto
roles/bigquery.jobUser proyecto
roles/bigquery.dataEditor dataset refugio_analitica
sa-deploy roles/run.developer proyecto
roles/artifactregistry.writer repositorio refugio-imagenes
roles/iam.serviceAccountUser sólo sobre sa-refugio-web y sa-job-nocturno

Cuatro cuentas, ningún rol primitivo, ninguna clave. sa-deploy se federa desde GitHub con WIF restringido al repositorio y a la rama main.

Datos: los esquemas de la sección 9. La tabla de ciclo de vida incluye una fila que conviene resaltar:

Dato Muere Mecanismo Verificación
Contacto del titular 6 meses tras la estancia UPDATE reserva SET nombre_titular='anonimizado', email_titular='[email protected]' WHERE fecha < NOW() - INTERVAL '6 months' en el job nocturno Consulta que cuenta filas con contacto y fecha antigua: debe dar 0

Esa columna de verificación es lo que convierte la política de retención en algo comprobable. Sin ella es una intención.

Nota sobre datos ficticios: los 2.000 registros se generan con data/seed/generar.py combinando listas de nombres inventados y correos @example.com (dominio reservado por el RFC 2606 precisamente para esto). Si el sistema tratase datos reales, harían falta: base jurídica del tratamiento, información al interesado, registro de actividades de tratamiento, contrato de encargo con Google Cloud, evaluación de impacto por el tratamiento de datos de localización de los refugios, y probablemente cifrado con claves gestionadas por el cliente (CMEK) en Cloud SQL y en los buckets. Nada de eso aplica aquí porque no hay datos personales reales, y esa es exactamente la razón por la que no los hay.

Solución 3 — Coste, SLO y ADR de RefugioReserva

La estimación, el hallazgo del balanceador y el ADR-006 completo están en la sección 14. La tabla final tras el recorte:

Servicio Coste/mes
Cloud SQL prod (db-f1-micro) 8,00 €
Cloud SQL dev (efímera, ~20 h/mes) 0,25 €
Cloud Run (prod + dev) 0,30 €
Cloud Storage 0,10 €
Artifact Registry 0,20 €
NL API (una vez) 0,40 €
BigQuery, Pub/Sub, Functions, Logging 0,00 €
Dominio (prorrateado) 1,00 €
Subtotal 10,25 €
Con margen del 25 % 12,81 €
Límite 12,00 €

Sigue justo por encima. Medida adicional aplicada, de la tabla de recortes: parada nocturna de Cloud SQL de producción entre las 01:00 y las 08:00 mediante un job programado, que reduce esa partida un 29 % (~2,30 €). Coste final estimado: 10,51 € con margen, dentro del límite. La consecuencia —la aplicación no funciona entre la 1 y las 8 de la madrugada— se documenta en el README y se declara explícitamente en el SLO: la ventana de medición excluye ese periodo, porque un SLO que se incumple por una parada planificada y conocida no mide nada útil.

Los cinco ADR de RefugioReserva:

ADR Decisión Factor determinante
ADR-001 Cloud Run para la aplicación Escala a cero con tráfico casi nulo
ADR-002 Cloud SQL PostgreSQL sobre Firestore Control de aforo con transacción y bloqueo de fila
ADR-003 Pub/Sub + Cloud Function sobre Dataflow 70 €/mes frente a 0 € para 60 mensajes al día
ADR-004 API de Natural Language sobre AutoML Cumple RF-6 en dos horas; AutoML son días y euros
ADR-005 Tres proyectos, europe-west1, nombres refugio-* Irreversible; se decide antes de crear nada
ADR-006 Sin balanceador permanente La restricción de coste es un requisito, no un obstáculo

Las cinco preguntas de control, respondidas:

  1. ¿Cuánto costará? 10,51 € al mes. La partida mayor es Cloud SQL (5,70 € tras la parada nocturna), seguida del dominio.
  2. ¿Si se cae la base de datos? Deja de funcionar la búsqueda de disponibilidad y la creación de reservas —el viaje crítico entero—. Siguen funcionando: la página estática de refugios (cacheada), las fotos del bucket y el panel de Looker Studio, que lee de BigQuery. La aplicación debe degradar con un mensaje claro, no con un error 500. Esto es una prueba de fiabilidad concreta para 08-04.
  3. ¿Quién puede leer los datos de usuarios? Mi cuenta personal (owner del proyecto), sa-refugio-web (a través de cloudsql.client + credenciales del secreto) y sa-job-nocturno. Nadie más. sa-procesar-evento y sa-deploy no tienen acceso a Cloud SQL, y el almacén analítico no contiene datos de contacto.
  4. ¿Qué descarté en la decisión más importante? En ADR-002, Firestore. Habría ahorrado 8 €/mes y todo el trabajo de red privada, pero el control de aforo con concurrencia —el corazón del problema— habría sido notablemente más frágil sin transacciones con bloqueo de fila. Acepté el coste y lo compensé con la parada nocturna.
  5. ¿Cómo me entero de que algo va mal? Alerta por correo cuando la tasa de error 5xx supere el 5 % durante 5 minutos, alerta de consumo de presupuesto de error del SLO al 50 %, uptime check cada 5 minutos contra /salud, y alerta de presupuesto de facturación al 50/90/100 % de 12 €.

Conclusión

Tienes el plano. Y, más importante, tienes las decisiones tomadas y escritas antes de que costaran dinero deshacerlas.

Sabes por qué se diseña antes de teclear: no por rigor académico, sino porque hay decisiones —projectId, región, CIDR, motor de base de datos, clave de partición— que cuestan diez segundos ahora y una reconstrucción completa después. Y sabes qué es "suficiente diseño": nueve artefactos, cinco a ocho horas, ninguno de más de una página, y la prueba de que está terminado son las cinco preguntas de control.

Sabes ir de los requisitos a los componentes lógicos antes de nombrar un solo producto de Google, y de ahí a los servicios con los árboles de decisión del curso —02-07 para cómputo, 02-06 para datos, 04-01 frente a 04-04 para analítica—, documentando siempre las cuatro columnas: qué eliges, por qué, qué descartas y por qué. Esa cuarta columna es la mitad del bloque A de la rúbrica y la pregunta literal de una entrevista.

Sabes dibujar los tres diagramas que sirven —contexto, componentes, despliegue—, cada uno con una pregunta y un nivel de detalle, con la regla de las 15 cajas y las cinco reglas de legibilidad, y en mermaid dentro del repositorio para que envejezcan con el código y no en un PNG olvidado.

Tienes decidida la estructura organizativa: cuántos proyectos y por qué dos es el equilibrio correcto, la región con su motivo escrito, la convención de nombres con las reglas duras de GCP (el projectId irrepetible, el nombre global de los buckets) y las etiquetas, con gestionado-por=terraform como detector de deriva gratuito.

Tienes la red diseñada sobre papel: el plan de direccionamiento con el /28 del conector y el rango de acceso privado a servicios que todo el mundo olvida, la matriz de flujos con denegación por defecto, y la superficie pública en cinco líneas.

Tienes la identidad en una tabla escrita antes de crear nada: una cuenta de servicio por carga de trabajo, ningún rol primitivo, cada permiso en el ámbito más estrecho, WIF sin claves y serviceAccountUser previsto para que el primer despliegue automatizado no te dé un 403 inexplicable.

Tienes el modelo de datos con qué vive dónde y por qué, el DDL operativo con sus restricciones y su índice parcial, la tabla analítica particionada con require_partition_filter como cinturón de seguridad de la factura, y —lo que casi nadie diseña— el ciclo de vida completo, incluida la eliminación, con su mecanismo y su consulta de verificación, y con la advertencia de RGPD que convierte la disciplina en hábito aunque tus datos sean inventados.

Tienes la estimación de coste hecha antes de gastar un euro, con los cuatro sumideros identificados y la tabla de recortes ordenada. Y tienes el ejemplo de RefugioReserva, donde la estimación reveló que el balanceador costaba el triple del presupuesto entero: exactamente el descubrimiento para el que sirve estimar antes.

Tienes tus SLO definidos con su SLI, su objetivo realista, su ventana y su presupuesto de error calculado, más la política que convierte ese presupuesto en decisiones.

Y tienes tus ADR, con la plantilla completa y con las dos secciones que la mayoría deja flojas: las consecuencias negativas —porque toda decisión pierde algo, y reconocerlo es criterio— y qué haría cambiar la decisión, que es lo que la mantiene viva.

En la próxima lección, 08-03, empiezas a construir. Y lo harás en un orden concreto y justificado —organización, red, identidad, estado de Terraform, datos, aplicación, entrega, analítica, IA, observabilidad— con fase 0 de preparación, ocho fases con su criterio de "hecho" verificable, las prácticas transversales que evitan que el proyecto se deforme por el camino, el método de cinco pasos para cuando te atasques, y el aviso más honesto del módulo: la primera vez, todo tarda el doble.

Guarda el diseño en el repositorio y haz commit. A partir de aquí, cada cosa que crees debe corresponderse con algo que ya está en este documento.

Curso de Google Cloud Platform (GCP)

Módulo 1: Introducción a Google Cloud Platform

Módulo 2: Servicios principales de GCP

Módulo 3: Redes y seguridad

Módulo 4: Datos y análisis

Módulo 5: Aprendizaje automático e IA

Módulo 6: DevOps y monitoreo

Módulo 7: Temas avanzados de GCP

Módulo 8: Proyecto final

© Copyright 2026. Todos los derechos reservados