Herramientas de usuario

Herramientas del sitio


clase:daw:daw-proyecto:tema04

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anteriorRevisión previa
Próxima revisión
Revisión previa
clase:daw:daw-proyecto:tema04 [2026/10/14 00:07] – Corregir escapes en monoespaciado claudeclase:daw:daw-proyecto:tema04 [2026/10/14 14:08] (actual) – Tema nuevo «2. IA y agentes»: los temas 2 a 7 pasan a ser 3 a 8, con sus referencias cruzadas renumeradas claude
Línea 1: Línea 1:
-====== 4. IA en el proyecto ======+====== 4. Docker en el proyecto ======
  
-Objetivo del tema: usar bien al agente para programar. No se enseña a programar; se enseña a **pedir** el trabajo de forma que salga bien y a comprobar que ha salido bien. Al acabar, el proyecto tiene su primer CRUD completo hecho así, y dos skills que recogen cómo se escribe el código en este proyecto.+Objetivo del tema: cada worktree tiene **su propia aplicación completa funcionando** (base de datos, backend y frontend), sin chocar con las de los demás worktrees. Al acabar, ''/git-flow start'' deja el worktree con sus puertos asignados y ''./app.sh start'' levanta la aplicación del issue con datos.
  
-Lo que ya está contado en el [[cursos:sdd:start|curso de programación con IA]] y aquí no se repite: qué es el [[cursos:sdd:10-spec-driven-development|Spec-driven development]] y por qué encaja con los agentes, los modos Plan y Build de [[cursos:sdd:03-opencode#plan_y_buildla_tecla_tab|OpenCode]], y la [[cursos:sdd:04-ingenieria#ingenieria_de_contexto|ingeniería de contexto]].+Lo que ya sabéis y aquí no se repite: imágenes y contenedores ([[clase:daw:daw:1eval:tema03|Despliegue 3]]), Dockerfile ([[clase:daw:daw:1eval:tema04|Despliegue 4]]), Docker Compose ([[clase:daw:daw:1eval:tema04.b|Despliegue 4.b]]) y redes y nginx-proxy ([[clase:daw:daw:1eval:tema04.c|Despliegue 4.c]]). Automatizar Maven y Node: [[clase:daw:proyecto:1eval:tema03|Proyecto 3]].
  
-===== Mini SDD con el modo plan =====+===== Tres contenedores =====
  
-Los frameworks de SDD completos (OpenSpec, Spec Kit, cc-sdd) generan requisitos, diseño y tareas en documentos separados. Para un proyecto de este tamaño, donde cada issue es un cambio pequeño o mediano, eso es más papeleo que trabajo. Lo que sí compensa, y es lo que se queda, son dos cosas:+La aplicación son tres contenedores, uno por caja del diagrama C4 de contenedores:
  
-  - **La intención escrita en un fichero** antes de tocar código, revisada por una persona. +^ Servicio ^ Imagen ^ Qué hace ^ 
-  - **Ejecutarla con el contexto limpio**, en una conversación nueva.+| ''db'' | ''mariadb'' | La base de datos. Solo accesible desde el backend | 
 +| ''backend'' | Construida: Maven → JRE | El JAR de Spring Boot en el puerto 8080 | 
 +| ''frontend'' | Construida: Angular → Nginx | Sirve el Angular compilado y hace de proxy de ''/api'' al backend |
  
-Ese es el flujo de cada issue:+El navegador solo habla con ''frontend''. Todo lo que empieza por ''/api'' lo reenvía Nginx al backend, así el frontend no necesita saber en qué puerto está el backend y no hay problemas de CORS.
  
-<uml> +Los dos Dockerfile son **multi-stage** y los escribe la IA. Lo único que hay que vigilar:
-start +
-:En el worktree del issue, +
-entrar en modo plan; +
-:Decir qué se quiere y pedir +
-que pregunte lo que no esté claro; +
-:El agente propone el plan; +
-repeat +
-  :Leerlo y corregirlo; +
-repeat while (¿hay algo que cambiar?) is (sí) +
-:Salir del modo plan: +
-el agente guarda planes/N-slug.md +
-y no hace nada más; +
-:/clear; +
-:Ejecuta @planes/N-slug.md; +
-:El agente implementa y pasa los tests; +
-stop +
-</uml>+
  
-==== 1. Planificar ====+<sxh bash;title:backend/Dockerfile> 
 +FROM maven:3.9-eclipse-temurin-25 AS build 
 +WORKDIR /app 
 +COPY pom.xml . 
 +RUN --mount=type=cache,target=/root/.m2 mvn -q dependency:go-offline 
 +COPY src ./src 
 +RUN --mount=type=cache,target=/root/.m2 mvn -q -DskipTests package
  
-En Claude Code, ''Shift+Tab'' hasta //plan mode//. En OpenCode, ''Tab'' hasta //Plan//. En ese modo el agente lee el proyecto y propone, pero no escribe código.+FROM eclipse-temurin:25-jre 
 +RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* 
 +COPY --from=build /app/target/*.jar /app.jar 
 +ENTRYPOINT ["java", "-jar", "/app.jar"] 
 +</sxh>
  
-Lo que se le dice:+El ''curl'' es para el ''healthcheck'' de abajo. El ''--mount=type=cache'' sobre ''.m2'' es lo que hace que reconstruir la imagen tarde segundos y no minutos: sin él, cada ''build'' vuelve a descargar todas las dependencias.
  
-<code> +<sxh bash;title:frontend/Dockerfile> 
-Quiero implementar el issue #12 (gh issue view 12). Antes de proponer nada, hazme +FROM node:22 AS build 
-las preguntas que necesites. El resultado de este plan es SOLO el fichero +WORKDIR /app 
-planes/12-alta-clientes.md: al aprobarlo, guárdalo y para. +COPY package*.json . 
-</code>+RUN npm ci 
 +COPY . . 
 +RUN npx ng build --configuration production
  
-El plan tiene que decir **qué** y **cómo**:+FROM nginx:alpine 
 +COPY nginx.conf /etc/nginx/conf.d/default.conf 
 +COPY --from=build /app/dist/frontend/browser /usr/share/nginx/html 
 +</sxh>
  
-  * Cambios en la base de datos (la migración), en el backend (qué clases en qué capas) y en el frontend (qué componentes y rutas). +<sxh plain;title:frontend/nginx.conf> 
-  * Las decisiones de diseño que haya tomado y por qué. +server { 
-  * Los **criterios de aceptación**: qué tiene que poder hacer el usuario cuando esté terminado, en frases comprobables («al guardar un cliente sin NIF, el formulario muestra el error y no se crea»). En el tema 5 esas frases se convierten en los tests E2E.+    listen 80; 
 +    root /usr/share/nginx/html;
  
-**Revisarlo es el trabajo humano del flujo.** Es mucho más barato corregir una frase del plan que corregir el código que sale de ella. Si el plan tiene algo que no convence, se le dice y se repite hasta que esté bien.+    location /api/ { 
 +        proxy_pass http://backend:8080/api/; 
 +    }
  
-==== 2. Guardar y limpiar ====+    location / { 
 +        try_files $uri $uri/ /index.html; 
 +    } 
 +} 
 +</sxh>
  
-Al aprobar el plan, el agente guarda ''planes/12-alta-clientes.md'' en el worktree y **se para**. Entonces ''/clear'' (''/new'' en OpenCode).+El ''try_files'' es obligatorio en una aplicación Angular: sin él, recargar el navegador en ''/clientes/12'' da un 404 de Nginx.
  
-Por qué: al salir del modo plan, por defecto el agente implementa en la **misma conversación**, arrastrando todo lo que ha leído y descartado mientras planificaba. Ese ruido empeora el resultado y encarece cada petición. Con el plan en un fichero, la conversación de planificar es desechable.+===== Producción y desarrollo con los mismos ficheros =====
  
-==== 3. Ejecutar ====+Docker Compose carga ''compose.yaml'' y, si existe, ''compose.override.yaml'' encima. Eso se usa así:
  
-<code> +  * ''compose.yaml'' **es producción**: imágenes construidas, la base de datos en una red interna sin puertos publicados, el frontend en la red de nginx-proxy con su ''VIRTUAL_HOST''. 
-Ejecuta @planes/12-alta-clientes.md. Al acabar, compila y pasa los tests. +  * ''compose.override.yaml'' **cambia lo de desarrollo**. Está en el repositorio y Compose lo carga solo. En el servidor, el workflow de despliegue (tema 7) fija ''COMPOSE_FILE=compose.yaml'' y el override no se aplica.
-</code>+
  
-El agente implementa con el contexto limpio: solo tiene ''AGENTS.md'', las skills de convenciones que carga y el plan. Cuando termina, el alumno prueba la aplicación en la URL del worktree y, si algo no está bien, se le pide en la misma conversación.+<sxh yaml;title:compose.yaml> 
 +services: 
 +  db: 
 +    image: mariadb:11 
 +    environment: 
 +      MARIADB_DATABASE: proyecto 
 +      MARIADB_USER: proyecto 
 +      MARIADB_PASSWORD: ${DB_PASSWORD} 
 +      MARIADB_ROOT_PASSWORD: ${DB_PASSWORD} 
 +    volumes: 
 +      - db-data:/var/lib/mysql 
 +    networks: 
 +      - interna 
 +    healthcheck: 
 +      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] 
 +      interval: 5s 
 +      retries: 20
  
-==== La carpeta planes/ ====+  backend: 
 +    build: ./backend 
 +    environment: 
 +      SPRING_DATASOURCE_URL: jdbc:mariadb://db:3306/proyecto 
 +      SPRING_DATASOURCE_USERNAME: proyecto 
 +      SPRING_DATASOURCE_PASSWORD: ${DB_PASSWORD} 
 +    depends_on: 
 +      db: 
 +        condition: service_healthy 
 +    networks: 
 +      - interna 
 +    healthcheck: 
 +      test: ["CMD", "curl", "-f", "http://localhost:8080/api/hola"] 
 +      interval: 5s 
 +      retries: 20
  
-''planes/'' es la versión mínima de la carpeta de especificaciones de un SDD. Se sube a git: el plan viaja con la rama, entra en ''develop'' en el mismo commit que el código y ''/revisar'' (tema 5) lo usa para comprobar que el código hace lo que se pidió.+  frontend: 
 +    build: ./frontend 
 +    environment: 
 +      VIRTUAL_HOST: <alumno>.proyectosdaw.cip.fpmislata.com 
 +    depends_on: 
 +      backend: 
 +        condition: service_healthy 
 +    networks: 
 +      - interna 
 +      - proxy
  
-Es un **registro** de lo que se pidió, no documentación: cuando el código cambie después, el plan no se actualiza. Para que el agente no se confunda con planes viejos, ''AGENTS.md'' lleva esta línea:+volumes: 
 +  db-data:
  
-<code> +networks: 
-planes/ es histórico: la fuente de verdad es el código. No leas planes antiguos salvo que te lo pidan. +  interna: 
-</code>+  proxy: 
 +    external: true 
 +    name: nginx-proxy-network 
 +</sxh>
  
-==== Cuándo usar el flujo ====+Los ''healthcheck'' con ''depends_on: condition: service_healthy'' hacen que el backend no arranque hasta que MariaDB acepte conexiones, y el frontend hasta que el backend responda. Sin eso, el backend muere al arrancar porque la base de datos aún no está lista.
  
-^ Tamaño del cambio ^ Cómo ^ +<sxh yaml;title:compose.override.yaml> 
-| Trivial: un texto, un color, una validación de un campo | Prompt directo, sin plan | +services: 
-| Todo lo demás | Plan → fichero → ''/clear'' → ejecutar | +  db: 
-| Un CRUD | ''/crud <Entidad>'' (tema 5), sin plan |+    ports: 
 +      - "${DB_PORT:-3306}:3306"
  
-===== El contexto del agente =====+  backend: 
 +    ports: 
 +      - "${BACKEND_PORT:-8080}:8080" 
 +    environment: 
 +      SPRING_PROFILES_ACTIVE: ${PERFIL:-datos-prueba}
  
-El contexto es todo lo que el modelo tiene delante en una conversación: ''AGENTS.md'', las skills cargadas, los ficheros que ha leído, la salida de los comandos que ha ejecutado y todo lo que se ha hablado. Cada mensaje lo reenvía entero. Cuanto más lleno, peor trabaja y más cuesta. Reglas:+  frontend: 
 +    build: 
 +      target: build 
 +    command: npx ng serve --host 0.0.0.0 --proxy-config proxy.conf.json 
 +    volumes: 
 +      - ./frontend:/app 
 +      - /app/node_modules 
 +    ports: 
 +      - "${FRONTEND_PORT:-4200}:4200" 
 +</sxh>
  
-  * **Una conversación por tarea.** ''/clear'' entre tareas. Lo que tenga que sobrevivir, a un fichero. +Lo que cambia en desarrollo:
-  * **El modelo bueno para planificar, el barato para ejecutar** cosas claras. ''/model'' en Claude Code, ''/models'' en OpenCode. +
-  * **No pegar logs enteros.** Solo el error y las líneas de alrededor. +
-  * **Mirar el contador.** ''/context'' y ''/cost'' en Claude Code; OpenCode lo muestra junto a la caja de entrada. Cuando el contexto pasa de la mitad, o se cierra la tarea o se hace ''/compact''.+
  
-===== Skills de convenciones =====+  * **Se publican los puertos**, para entrar desde el navegador y para que Maven y Playwright lleguen a la base de datos y al frontend desde el host. 
 +  * **El frontend pasa a ''ng serve''** con la carpeta local ''frontend/'' montada dentro: al guardar un fichero, el navegador se recarga. ''proxy.conf.json'' manda ''/api'' a ''%%http://backend:8080%%''. El volumen anónimo sobre ''node_modules'' evita que los módulos instalados en la imagen se tapen con los del host. 
 +  * **El backend no tiene recarga en caliente**: cada cambio en Java es ''docker compose up --build backend''. Con la caché de Maven son unos segundos. Y no pasa nada. 
 +  * **Datos de prueba** activados (abajo).
  
-El agente escribe código de cualquier manera si no se le dice cómo se hace **en este proyecto**. Y decírselo en cada prompt no escala. Para eso están dos **skills de conocimiento** (no se invocan: el agente las carga solo cuando va a tocar backend o frontend):+<note important>La red ''nginx-proxy-network'' es externa: en el servidor la crea nginx-proxy, pero en el portátil hay que crearla una vez, ''docker network create nginx-proxy-network'', o Compose se niega a arrancar. ''app.sh start'' lo hace si no existe.</note>
  
-^ Skill ^ Qué contiene ^ +===== Un compose por worktree =====
-| ''convenciones-backend'' | Las capas ''controller'' / ''domain'' / ''persistence''; el ''Repository'' se define en ''domain'' y se implementa en ''persistence''; DTO ''XxxRequest'' / ''XxxResponse''; entidades ''XxxJpaEntity''; MapStruct para convertir; ''ApiExceptionHandler'' para los errores; cómo se nombra cada clase y en qué paquete va; cómo se escriben las migraciones y los datos de prueba | +
-| ''convenciones-frontend'' | Estructura de un componente, nombres de ficheros, rutas, servicios, cómo se llama a la API, formularios y validación; y la regla de selectores para los tests: todo elemento que un test E2E vaya a tocar lleva ''data-testid'', nunca se selecciona por clase CSS |+
  
-La arquitectura es la que ya conocéis de Programación y DWS: aquí no se inventa una nueva.+Dos worktrees con el mismo ''compose.yaml'' crearían contenedores con el mismo nombre y pedirían los mismos puertos. Lo resuelve un fichero ''.env'' **en cada worktree**, ignorado por git, que Compose lee solo:
  
-**Se escriben a partir del código, no de la teoría.** Después del primer CRUD, revisado y corregido hasta que esté como tiene que estar, se le pide al agente: «lee el CRUD de clientes y escribe la skill ''convenciones-backend'' describiendo cómo está hecho, para que el siguiente salga igual». El alumno corrige lo que no sea una convención sino una casualidad.+<sxh bash;title:.env> 
 +COMPOSE_PROJECT_NAME=mi-proyecto-12-alta-clientes 
 +DB_PORT=33112 
 +BACKEND_PORT=8112 
 +FRONTEND_PORT=4212 
 +DB_PASSWORD=dev 
 +</sxh>
  
-La ''description'' de una skill de conocimiento dice **cuándo cargarla**:+  * ''COMPOSE_PROJECT_NAME'' es el prefijo de contenedores, redes y volúmenes de ese worktree. Dos proyectos distintos no se tocan. 
 +  * Los puertos los busca ''/git-flow start'' al crear el worktree: prueba a partir de una base y se queda con los libres. 
 +  * Las variables llevan valor por defecto, ''${BACKEND_PORT:-8080}'', para cuando no hay ''.env'': en CI (tema 7).
  
-<sxh yaml> +''/git-flow finish'' termina con ''docker compose down -v'': se van los contenedores **y el volumen** de la base de datos de ese worktree. No queda nada. 
---- + 
-name: convenciones-backend +===== La primera tabla ===== 
-description: Cómo se escribe el código del backend en este proyecto (capas, nombres, DTO, migraciones). Cargar siempre antes de crear o modificar cualquier clase Java o fichero SQL. + 
----+Hasta ahora el backend no tiene base de datos. Se añaden ahora, con un prompt directo al agente (el flujo de trabajo de verdad llega en el tema 5; esto es solo para tener algo que ver): 
 + 
 +  * Dependencias ''spring-boot-starter-data-jpa'', ''mariadb-java-client'' y ''flyway-mysql''. 
 +  * Una migración ''%%backend/src/main/resources/db/migration/V1__clientes.sql%%'' con una tabla. 
 +  * Un ''GET /api/clientes'' que la lista y una página de Angular que la muestra. 
 + 
 +El esquema **siempre** va en migraciones de Flyway, ''%%V<n>__descripcion.sql%%'', y nunca con ''ddl-auto''. Así cada worktree, cada runner de CI y el servidor construyen la misma base de datos desde cero. 
 + 
 +===== Datos de prueba ===== 
 + 
 +Cada worktree arranca con la base de datos vacía: no hay nada que ver en la aplicación ni se pueden escribir tests E2E que dependan de que exista un cliente. Los datos de prueba se separan del esquema: 
 + 
 +<code> 
 +backend/src/main/resources/db/ 
 +├── migration/            <- esquema: V1__clientes.sql, V2__pedidos.sql ... 
 +└── datos-prueba/         <- datos: R__clientes.sql, R__pedidos.sql ... 
 +</code> 
 + 
 +Los de ''datos-prueba/'' son migraciones **repetibles** de Flyway (''%%R__%%''): se ejecutan después de todas las versionadas, y como la base de datos de un worktree siempre nace vacía, se ejecutan una vez. Flyway solo mira esa carpeta cuando está activo el perfil ''datos-prueba'': 
 + 
 +<sxh plain;title:application-datos-prueba.properties> 
 +spring.flyway.locations=classpath:db/migration,classpath:db/datos-prueba
 </sxh> </sxh>
  
-===== MCP =====+  * En desarrollo el perfil lo activa ''compose.override.yaml''. Para probar la aplicación vacía: ''PERFIL=default docker compose up -d --build backend''. 
 +  * En producción ''compose.yaml'' no activa el perfil: los datos de prueba **nunca llegan al servidor**. 
 +  * Para volver al estado inicial (antes de pasar los E2E, por ejemplo): ''docker compose down -v && docker compose up -d''.
  
-Dos servidores MCP y ninguno más (qué es un MCP: [[cursos:sdd:02-skills-agentes-mcp#mcp|MCP]]):+Cada entidad nueva trae su ''%%R__<entidad>.sql%%'' con unos cuantos registros; el steering de cc-sdd (tema 6) obliga a que cada CRUD lo traiga.
  
-  * **Context7**: documentación actualizada de Spring Boot y Angular. Sin él, el agente escribe código de la versión que recuerda, que no es la que usáis. +===== El script app.sh =====
-  * **Playwright MCP**: el agente abre la aplicación en un navegador y la ve. Sirve para que compruebe por sí mismo que una pantalla funciona, y en el tema 5 para generar los tests E2E.+
  
-Se configuran con ''claude mcp add'' en Claude Code y en ''opencode.json'' en OpenCode, siguiendo la página de cada servidor.+Operar la aplicación es siempre lo mismo y no necesita ninguna inteligencia, así que no es una skill: es un script de bash en la raíz del repositorio, con cuatro subcomandos y la gramática del tema 1. Bash está en los tres sistemas (en Windows lo trae Git, tema 3). Y es el mismo script que se usa en el servidor (tema 7): no hay una forma de operar en local y otra en producción.
  
-===== Permisos del agente =====+<sxh bash;title:app.sh> 
 +#!/bin/bash 
 +# La aplicación de este worktree: start | stop [-v] | status | logs 
 +set -e 
 +cd "$(dirname "$0")" 
 +case "$1" in 
 +  start) 
 +    docker network inspect nginx-proxy-network >/dev/null 2>&1 || docker network create nginx-proxy-network 
 +    docker compose up -d --build --wait 
 +    [ -f .env ] && . ./.env 
 +    echo "Aplicación en http://localhost:${FRONTEND_PORT:-4200}" ;; 
 +  stop)   shift; docker compose down "$@" ;; 
 +  status) docker compose ps ;; 
 +  logs)   docker compose logs --tail=200 ;; 
 +  *)      echo "uso: $0 start | stop [-v] | status | logs"; exit 1 ;; 
 +esac 
 +</sxh>
  
-En el tema 1 se permitió lo básico. Para programar, el agente tiene que poder compilar, pasar tests y levantar la aplicación sin preguntar en cada paso. La lista de ''.claude/settings.json'' queda así:+  * ''./app.sh start'' vale para todo: la primera vez, después de cambiar el backend (reconstruye la imagen y la vuelve a levantar) y al día siguiente tras un ''stop''. ''--wait'' espera a los ''healthcheck'', así que cuando escribe la URL la aplicación ya responde. 
 +  * ''./app.sh stop'' para los contenedores y conserva la base de datos. ''./app.sh stop -v'' la borra también: es lo que hace ''/git-flow finish'' al cerrar el issue, y lo que se hace para volver a los datos de prueba iniciales. 
 +  * ''./app.sh status'' y ''./app.sh logs'' son lo primero que se mira cuando algo no responde. 
 +  * Trabaja sobre la carpeta en la que está y lee su ''.env'', así que cada worktree opera el suyo. En el servidor no hay ''.env'': valen los valores por defecto. 
 + 
 +<note>Los scripts se guardan con finales de línea de Linux o bash en Windows no los entiende. Una línea en ''.gitattributes'' lo garantiza para todos: ''*.sh text eol=lf''.</note> 
 + 
 +===== Dónde corren Maven y los tests ===== 
 + 
 +Las imágenes son de **ejecución**: el backend es un JRE sin Maven y el frontend es Nginx. Así que compilar y pasar tests se hace **en el host**, que para eso están instalados el JDK, Maven y Node: 
 + 
 +^ Qué ^ Dónde ^ Contra qué ^ 
 +| ''mvn test'' (unitarios y ArchUnit) | ''backend/'' del worktree | Nada: no necesitan la aplicación levantada | 
 +| ''npm run test:api'' (API) | ''frontend/'' del worktree | ''%%http://localhost:$FRONTEND_PORT/api%%'' | 
 +| ''npm run test:e2e'' (E2E) | ''frontend/'' del worktree | ''%%http://localhost:$FRONTEND_PORT%%'' | 
 + 
 +Son los tres comandos de tests del proyecto. Maven y npm funcionan igual en Linux, Windows y Mac, y son lo que ejecutan el alumno, el agente y CI (tema 7). ''mvn test'' forma parte del build y corre en cada compilación. Los de API y los E2E **no forman parte del build**: se lanzan aparte, cuando se quiere, con los otros dos comandos. Los dos son de Playwright y atacan la aplicación levantada del worktree (tema 6). En el tema 6 la skill ''/test'' los envuelve con la gramática del tema 1 (''/test api run'') y explica lo que sale en rojo; CI los ejecuta tal cual. 
 + 
 +==== npm run ==== 
 + 
 +''npm run <nombre>'' ejecuta un comando guardado en la sección ''scripts'' del ''package.json''. Es la forma de tener en el proyecto los comandos largos con un nombre corto, sin depender del sistema operativo: npm los ejecuta desde la carpeta del ''package.json'' y con los programas de ''node_modules/.bin'' en el PATH, así que ''playwright'' se escribe sin ''npx''. 
 + 
 +<sxh json;title:frontend/package.json> 
 +"scripts": { 
 +  "start": "ng serve", 
 +  "build": "ng build", 
 +  "test:api": "docker compose down -v && docker compose up -d --wait && playwright test --project=api", 
 +  "test:e2e": "docker compose down -v && docker compose up -d --wait && playwright test --project=e2e" 
 +} 
 +</sxh>
  
-  * **Permitido**: ''mvn'', ''npm'', ''npx'' (incluido ''npx playwright''), ''docker compose'', ''gh issue'', ''gh run'' y las lecturas de git (''status'', ''diff'', ''log'', ''worktree list''). +Los dos scripts resetean la base de datos del worktree, esperan a que la aplicación esté sana y pasan los tests de un proyecto de Playwright (''api'' o ''e2e'', tema 6). El ''&&'' lo entienden igual ''cmd'' y bash. ''npm run'' sin nombre lista los scripts que hay. ''start'' y ''build'' ya los trae Angular: son los que ejecutan ''npm start'' y ''npm run build''.
-  * **Pregunta**: escribir ficheros fuera del worktree, ''docker'' a secas, cualquier ''curl'' a un sitio que no sea ''localhost''. +
-  * **Denegado**: ''git push --force'', ''rm -rf'', y cualquier ''git'' que cambie el repositorio (''commit'', ''merge'', ''push''), que solo puede ejecutar ''/git-flow'' por su ''allowed-tools''.+
  
-En OpenCode, lo mismo en la clave ''permission'' de ''opencode.json''.+Esto va en ''AGENTS.md'' tal cual, porque es lo que el agente ejecuta para comprobar su trabajo. Si no lo sabe, intentará ''mvn test'' dentro del contenedor y fallará, o ni probará.
  
 ===== Ejercicios ===== ===== Ejercicios =====
  
 ==== Ejercicio 1 ==== ==== Ejercicio 1 ====
-  * Configura Context7 y el MCP de Playwright en Claude Code (''claude mcp add'') y en OpenCode (''opencode.json''). +  * Crea un issue «Aplicación en Docker» e inícialo con ''/git-flow''. 
-  * Comprueba que funcionan: pide al agente la forma actual de declarar una ruta en Angular y que abra la aplicación del worktree y te diga qué ve. +  * Pide al agente los dos ''Dockerfile'', ''compose.yaml'', ''compose.override.yaml'', ''frontend/nginx.conf'' y ''frontend/proxy.conf.json'' siguiendo este tema. Revisa que el backend tiene la caché de ''.m2'', que ''db'' no publica puertos en ''compose.yaml'' y que ''nginx.conf'' tiene el ''try_files''. 
-  * Completa ''.claude/settings.json'' con los permisos de este tema y súbelo.+  * Añade ''.env'' al ''.gitignore'' y crea uno a mano en el worktree con ''COMPOSE_PROJECT_NAME'', los tres puertos y ''DB_PASSWORD''. 
 +  * ''docker network create nginx-proxy-network'' y ''docker compose up -d --build''. Comprueba con ''docker compose ps'' que los tres servicios están //healthy//. 
 +  * Entra en ''%%http://localhost:<FRONTEND_PORT>%%'' y comprueba que se ve el ''/api/hola''.
  
 ==== Ejercicio 2 ==== ==== Ejercicio 2 ====
-  * Crea un issue para la primera entidad de tu proyecto con un CRUD completo (por ejemplo «CRUD de productos») e inícialo. +  * En el mismo worktree, pide al agente que añada JPA, MariaDB y Flyway, la migración ''%%V1__clientes.sql%%'', un ''GET /api/clientes'' y una página de Angular que liste los clientes. 
-  * Entra en modo plan y pide el plan con el prompt del tema: que pregunte lo que no esté claro y que el resultado sea solo ''planes/<N>-<slug>.md''. +  * Crea ''application-datos-prueba.properties'' y ''db/datos-prueba/%%R__clientes.sql%%'' con cinco clientes. 
-  * Lee el plan. Comprueba que tiene migración, clases por capas, componentes y rutas, y criterios de aceptación comprobables. Corrige hasta que esté bien. +  * ''docker compose up -d --build backend'' y comprueba que la lista muestra los cinco clientes. 
-  * Sal del modo plan, comprueba que el fichero existe y que el agente no ha tocado nada más. +  * Arranca con ''PERFIL=default'' tras un ''down -v'' y comprueba que la lista sale vacía. Vuelve a dejarlo con datos. 
-  * ''/clear'' y ''Ejecuta @planes/<N>-<slug>.md''. +  * Cambia un texto de la página de Angular, guarda y comprueba que el navegador se recarga solo.
-  * Prueba la aplicación en la URL del worktree: listado, alta, edición, borrado y las validaciones. Lo que no esté bien se pide en la misma conversación. +
-  * Lee el código generado clase por clase: es la referencia de todos los CRUD que vienen después.+
  
 ==== Ejercicio 3 ==== ==== Ejercicio 3 ====
-  * Pide al agente: «lee el CRUD de <entidad> y escribe la skill ''convenciones-backend'' describiendo cómo está hecho, para que el siguiente salga igual». Lo mismo para ''convenciones-frontend'', incluyendo la regla de ''data-testid''. +  * Añade a ''application.properties'' la URL con ''${DB_PORT:3306}'' y ejecuta ''mvn test'' desde ''backend/''. Tiene que pasar sin nada levantado. 
-  * Revisa las dos: quita lo que sea casualidad y no convención. Comprueba que la ''description'' dice cuándo cargarlas. +  * Escribe en ''AGENTS.md'': que la aplicación se opera con ''./app.sh start | stop | status | logs'', que los tests se lanzan en el host con ''mvn test'', ''npm run test:api'' y ''npm run test:e2e'', y que el esquema va siempre en migraciones. 
-  * ''/clear'' y pide un cambio pequeño en el backend. Comprueba que el agente carga ''convenciones-backend'' sin que se lo digas.+  * ''/git-flow commit'' y ''/git-flow finish''.
  
 ==== Ejercicio 4 ==== ==== Ejercicio 4 ====
-  * Añade a ''AGENTS.md'' la línea sobre ''planes/''. +  * Escribe ''app.sh'' y el ''.gitattributes''. Pruébalos: arrancar, cambiar un texto del backend, volver a arrancar y ver el cambio; parar, arrancar y ver que los datos siguen; parar con ''-v'', arrancar y ver los datos de prueba de nuevo. 
-  * ''/git-flow commit'' y ''/git-flow finalizar''. Comprueba que el plan ha entrado en ''develop'' en el mismo commit que el código. +  * Amplía ''/git-flow'': ''start'' escribe el ''.env'' del worktree buscando puertos libres y dice cómo arrancar; ''finish'' ejecuta ''./app.sh stop -v'' antes de borrar el worktree. 
-  * Mira ''/context'' al final de la conversación de ejecución y anota cuánto ha ocupado.+  * Finaliza el issue. 
 + 
 +==== Ejercicio 5 ==== 
 +  * Crea dos issues cualesquiera, inícialos y arranca los dos con ''./app.sh start''. Comprueba que cada worktree tiene su ''.env'' con puertos distintos y que las dos aplicaciones están levantadas a la vez (''docker ps''). 
 +  * Cambia los datos de prueba en uno de los dos y comprueba que el otro no se entera. 
 +  * Finaliza los dos y comprueba con ''docker ps -a'' y ''docker volume ls'' que no queda nada de ellos.
  
clase/daw/daw-proyecto/tema04.1791929245.txt.gz · Última modificación: por claude