
# GreenITESO · Evidencia del estado actual

Fecha: 9 octubre 2026. Entorno local aislado con PostgreSQL 18 y datos sintéticos.

## Alcance

Todas las rutas fueron visitadas en escritorio/móvil. Esto no equivale a comprobar todos los controles, navegadores, requisitos ni producción. El login institucional conserva evidencia anterior y no cuenta como prueba actual.
697 pruebas del backend pasaron. Suite frontend: 69 pasaron y 11 fallaron; varias expectativas necesitan preparación de sesión o actualización de rutas. Build de producción correcto.

## Revisiones

- frontend · `dev` · `5930f50c60bd73741c0656a3b20da689700c66cc`
- backend · `dev` · `1e56ffb9fa8fc344d111d001a79c04a79bbe40b2`
- infra · `main` · `30825daaae38eb9777247248dca50e72907ebfbc`

## Resultados

| Caso | Resultado | Función | Evidencia |
|---|---|---|---|
| QA01 | PASS | Compilación de producción del frontend | [Ver](evidence/final-QA01.json) |
| QA02A | PASS | Catálogo sin sesión | [Ver](evidence/final-QA02A.json) |
| QA03 | PASS | Catálogo UI con backend real | [Ver](evidence/final-QA03.json) |
| QA04 | FAIL | Registro UI persiste una acción | [Ver](evidence/final-QA04.json) |
| QA05A | PASS | Acción sin fotografía acredita puntos | [Ver](evidence/final-QA05A.json) |
| QA05B | PASS | Reintento idempotente de acción | [Ver](evidence/final-QA05B.json) |
| QA06A | PASS | Referencia PHOTO queda pendiente sin acreditar | [Ver](evidence/final-QA06A.json) |
| QA06B | PASS | Estudiante no puede auditar | [Ver](evidence/final-QA06B.json) |
| QA06C | FAIL | Bandeja UI de auditoría carga pendientes | [Ver](evidence/final-QA06C.json) |
| QA06D | PASS | Administrador aprueba PHOTO por API | [Ver](evidence/final-QA06D.json) |
| QA06E | PASS | Revocación revierte puntos y misión | [Ver](evidence/final-QA06E.json) |
| QA07A | PASS | Progreso de misión derivado de acción aprobada | [Ver](evidence/final-QA07A.json) |
| QA07B | PASS | Inscripción a campaña desde UI | [Ver](evidence/final-QA07B.json) |
| QA08A | PASS | Ranking de usuarios | [Ver](evidence/final-QA08A.json) |
| QA08B | PASS | Ranking de equipos disponible en UI | [Ver](evidence/final-QA08B.json) |
| QA09A | PASS | Crear publicación propia en feed | [Ver](evidence/final-QA09A.json) |
| QA09B | PASS | Otro usuario no edita publicación ajena | [Ver](evidence/final-QA09B.json) |
| QA09C | PASS | Autor edita publicación por API | [Ver](evidence/final-QA09C.json) |
| QA09D | PASS | Autor dispone de controles de edición en UI | [Ver](evidence/final-QA09D.json) |
| QA10A | PASS | Evento de insignia persistido y consultable | [Ver](evidence/final-QA10A.json) |
| QA10B | FAIL | UI refleja notificaciones reales | [Ver](evidence/final-QA10B.json) |
| QA11A | PASS | Perfil editable por propietario | [Ver](evidence/final-QA11A.json) |
| QA11B | PASS | Consulta del perfil e impacto aprobado | [Ver](evidence/final-QA11B.json) |
| QA11C | PASS | Límite de un liderazgo privado por usuario | [Ver](evidence/final-QA11C.json) |
| QA12A | FAIL | Administrador modifica catálogo y persiste | [Ver](evidence/final-QA12A.json) |
| QA02B | PASS | Estudiante no accede a pantalla administrativa | [Ver](evidence/final-QA02B.json) |
| QA11D | PASS | Crear clan privado con usuario elegible | [Ver](evidence/final-QA11D.json) |
| QA11E | PASS | No propietario no elimina clan privado | [Ver](evidence/final-QA11E.json) |
| QA11F | PASS | Propietario elimina clan mediante borrado lógico | [Ver](evidence/final-QA11F.json) |
| QA10C | FAIL | Perfil muestra insignias ganadas | [Ver](evidence/final-QA10C.json) |
| QA13 | NOT RUN | Despliegue real / infraestructura compartida | [Ver](evidence/final-QA13.json) |
| QA14 | PASS | Dashboard con sesión y backend real | [Ver](evidence/final-QA14.json) |
| QA15 | PASS | Perfil y recarga conservan biografía | [Ver](evidence/final-QA15.json) |
| QA16A | PASS | Ruta protegida sin sesión | [Ver](evidence/final-QA16A.json) |
| QA16B | PASS | Login institucional configurado | [Ver](evidence/final-QA16B.json) |
| QA16C | PASS | Backend Entra rechaza identidad mock | [Ver](evidence/final-QA16C.json) |
| QA16G | FAIL | Dos renovaciones consecutivas desde el cliente real | [Ver](evidence/final-QA16G.json) |
| QA17A | PASS | Listado de amistades | [Ver](evidence/final-QA17A.json) |
| QA17B | PASS | Solicitud de amistad entre dos usuarios | [Ver](evidence/final-QA17B.json) |
| QA17C | PASS | Solicitante no acepta su propia solicitud | [Ver](evidence/final-QA17C.json) |
| QA17D | PASS | Destinatario acepta amistad | [Ver](evidence/final-QA17D.json) |
| QA17E | PASS | Amistad visible tras nueva lectura | [Ver](evidence/final-QA17E.json) |
| QA18A | PASS | Unirse a clan público | [Ver](evidence/final-QA18A.json) |
| QA18B | PASS | Membresía visible en detalle | [Ver](evidence/final-QA18B.json) |
| QA18C | PASS | Salir del clan | [Ver](evidence/final-QA18C.json) |
| QA18D | PASS | Líder no abandona sin transferencia | [Ver](evidence/final-QA18D.json) |
| QA19A | PASS | Canje en tienda persiste inventario y saldo tras recarga | [Ver](evidence/final-QA19A.json) |
| QA19B | PASS | Canje repetido no descuenta de nuevo | [Ver](evidence/final-QA19B.json) |
| QA19C | PASS | Canje sin saldo suficiente | [Ver](evidence/final-QA19C.json) |
| QA20 | PASS | Catálogo en móvil sin desborde horizontal | [Ver](evidence/final-QA20.json) |
| QA21A | PASS | Notificaciones persistidas consultables | [Ver](evidence/final-QA21A.json) |
| QA21B | PASS | Otro usuario no marca notificación ajena | [Ver](evidence/final-QA21B.json) |
| QA21C | PASS | Marcar notificación como leída | [Ver](evidence/final-QA21C.json) |
| QA21D | PASS | Eliminar notificación propia | [Ver](evidence/final-QA21D.json) |
| QA21E | PASS | Notificación eliminada excluida tras lectura | [Ver](evidence/final-QA21E.json) |
| QA21F | PASS | Marcar todas las notificaciones | [Ver](evidence/final-QA21F.json) |
| QA21G | PASS | Contador sin pendientes | [Ver](evidence/final-QA21G.json) |
| QA22 | PASS | Catálogo de insignias | [Ver](evidence/final-QA22.json) |
| QA23 | PASS | Estudiante no modifica catálogo administrativo | [Ver](evidence/final-QA23.json) |
| QA24A | PASS | Otro usuario no elimina publicación ajena | [Ver](evidence/final-QA24A.json) |
| QA24B | PASS | Autor elimina publicación | [Ver](evidence/final-QA24B.json) |
| QA25A | PASS | Segundo registro dentro de cuota | [Ver](evidence/final-QA25A.json) |
| QA25B | PASS | Tercer registro dentro de cuota | [Ver](evidence/final-QA25B.json) |
| QA25C | PASS | Cuarto registro excede límite diario de tres | [Ver](evidence/final-QA25C.json) |
| QA26A | PASS | Administrador crea campaña con misión desde UI | [Ver](evidence/final-QA26A.json) |
| QA26B | PASS | Administrador edita campaña en promoción desde UI | [Ver](evidence/final-QA26B.json) |
| QA27A | PASS | Estudiante envía propuesta global desde UI | [Ver](evidence/final-QA27A.json) |
| QA27B | PASS | Administrador aprueba propuesta desde Auditoría | [Ver](evidence/final-QA27B.json) |
| QA27C | PASS | Propuesta aprobada aparece como campaña pública | [Ver](evidence/final-QA27C.json) |
| QA27D | PASS | Segunda propuesta para revisar rechazo | [Ver](evidence/final-QA27D.json) |
| QA27E | PASS | Administrador rechaza propuesta con motivo desde UI | [Ver](evidence/final-QA27E.json) |
| QA27F | PASS | Proponente consulta el motivo de rechazo | [Ver](evidence/final-QA27F.json) |
| QA27G | PASS | Estudiante no aprueba propuestas | [Ver](evidence/final-QA27G.json) |
| QA28A | PASS | Feed evita publicar contenido vacío | [Ver](evidence/final-QA28A.json) |
| QA29A | PASS | Consultar cuenta autenticada | [Ver](evidence/final-QA29A.json) |
| QA29B | PASS | Directorio reservado al administrador | [Ver](evidence/final-QA29B.json) |
| QA29C | PASS | Administrador consulta directorio | [Ver](evidence/final-QA29C.json) |
| QA29D | PASS | Estudiante no cambia roles | [Ver](evidence/final-QA29D.json) |
| QA29E | PASS | Administrador cambia rol de cuenta sintética | [Ver](evidence/final-QA29E.json) |
| QA29F | PASS | Historial de cambio de rol consultable | [Ver](evidence/final-QA29F.json) |
| QA29G | PASS | No se elimina el último administrador | [Ver](evidence/final-QA29G.json) |
| QA29H | PASS | Restaurar rol de cuenta sintética | [Ver](evidence/final-QA29H.json) |
| QA30A | PASS | Consultar clan institucional asignado | [Ver](evidence/final-QA30A.json) |
| QA30B | PASS | Carrera vacía rechazada en onboarding | [Ver](evidence/final-QA30B.json) |
| QA30C | PASS | Detalle y roster de clan privado | [Ver](evidence/final-QA30C.json) |
| QA31A | PASS | Líder crea campaña privada para su clan | [Ver](evidence/final-QA31A.json) |
| QA31B | PASS | No miembro no se inscribe a campaña privada | [Ver](evidence/final-QA31B.json) |
| QA31D | PASS | Campaña sin misiones rechazada | [Ver](evidence/final-QA31D.json) |
| QA31E | PASS | Campaña con fechas invertidas rechazada | [Ver](evidence/final-QA31E.json) |
| QA31F | PASS | Participantes de campaña consultables | [Ver](evidence/final-QA31F.json) |
| QA31G | PASS | Misiones de campaña consultables | [Ver](evidence/final-QA31G.json) |
| QA32A | PASS | Categorías de acciones consultables | [Ver](evidence/final-QA32A.json) |
| QA33home | PASS | Ruta auxiliar /home | [Ver](evidence/final-QA33home.json) |
| QA33designsystem | PASS | Ruta auxiliar /design-system | [Ver](evidence/final-QA33designsystem.json) |
| QA33shop | PASS | Ruta auxiliar /shop | [Ver](evidence/final-QA33shop.json) |
| QA34A | PASS | Cerrar sesión desde menú elimina sesión y vuelve a login | [Ver](evidence/final-QA34A.json) |
| QA35A | PRIOR VERIFIED | Microsoft institucional real: callback, intercambio y recarga | [Ver](evidence/final-QA35A.json) |
| QA31C | PASS | Creador de campaña privada inscrito automáticamente | [Ver](evidence/final-QA31C.json) |
| QA30D | PASS | Declarar carrera asigna clan institucional | [Ver](evidence/final-QA30D.json) |
| QA30E | PASS | Repetir carrera conserva la asignación institucional | [Ver](evidence/final-QA30E.json) |
| QA36A | PASS | Crear clan con acceso por solicitud | [Ver](evidence/final-QA36A.json) |
| QA36B | PASS | Solicitud de acceso queda pendiente | [Ver](evidence/final-QA36B.json) |
| QA36C | PASS | Líder rechaza solicitud de acceso | [Ver](evidence/final-QA36C.json) |
| QA36D | PASS | Solicitante puede volver a pedir acceso | [Ver](evidence/final-QA36D.json) |
| QA36E | PASS | Líder acepta solicitud y activa membresía | [Ver](evidence/final-QA36E.json) |
| QA36F | PASS | Elegir clan privado activo | [Ver](evidence/final-QA36F.json) |
| QA36G | PASS | Transferir liderazgo a miembro aceptado | [Ver](evidence/final-QA36G.json) |
| QA28B | PASS | Publicar desde feed y conservar tras recarga | [Ver](evidence/final-QA28B.json) |
| QA34B | PASS | Logout invalida refresh token en backend | [Ver](evidence/final-QA34B.json) |
| QA37A | PASS | Autenticación WebSocket de student | [Ver](evidence/final-QA37A.json) |
| QA37B | PASS | Autenticación WebSocket de outsider | [Ver](evidence/final-QA37B.json) |
| QA37C | PASS | Ping del WebSocket responde pong | [Ver](evidence/final-QA37C.json) |
| QA37D | PASS | Aprobar evidencia entrega notificación por WebSocket | [Ver](evidence/final-QA37D.json) |
| QA37E | PASS | Usuario ajeno no recibe notificación del estudiante | [Ver](evidence/final-QA37E.json) |
| QA37F | PASS | Token inválido cierra WebSocket | [Ver](evidence/final-QA37F.json) |
| QA37G | PASS | Mensaje previo a autenticación cierra WebSocket | [Ver](evidence/final-QA37G.json) |
| QA38A | FAIL | Administrador crea una definición de acción | [Ver](evidence/final-QA38A.json) |
| QA38B | FAIL | Eliminar acción referenciada responde con error controlado | [Ver](evidence/final-QA38B.json) |
| QA26C | PASS | Administrador agrega misión a campaña en promoción desde UI | [Ver](evidence/final-QA26C.json) |
| CLAN-01 | PASS | Crear clan valida nombre vacío | [Ver](evidence/CLAN-01.json) |
| CLAN-02 | PASS | Crear clan público desde pantalla | [Ver](evidence/CLAN-02.json) |
| CLAN-03 | PASS | Copiar invitación del clan | [Ver](evidence/CLAN-03.json) |
| CLAN-04 | PASS | Buscar y unirse al clan público | [Ver](evidence/CLAN-04.json) |
| CLAN-05 | PASS | Seleccionar clan activo conserva estado tras recarga | [Ver](evidence/CLAN-05.json) |
| CLAN-06 | PASS | Transferir liderazgo desde pantalla | [Ver](evidence/CLAN-06.json) |
| CLAN-07 | PASS | Cancelar salida conserva membresía | [Ver](evidence/CLAN-07.json) |
| CLAN-08 | PASS | Salir del clan tras transferir liderazgo | [Ver](evidence/CLAN-08.json) |
| CLAN-09 | PASS | Disolver clan con confirmación | [Ver](evidence/CLAN-09.json) |
| CLAN-10 | PASS | Clan disuelto muestra estado no disponible | [Ver](evidence/CLAN-10.json) |
| FEED-01 | PASS | Publicar desde el feed | [Ver](evidence/FEED-01.json) |
| FEED-02 | PASS | Editar publicación propia y recargar | [Ver](evidence/FEED-02.json) |
| FEED-03 | PASS | Eliminar publicación propia | [Ver](evidence/FEED-03.json) |
| CLAN-11 | PASS | Invitación inválida muestra explicación | [Ver](evidence/CLAN-11.json) |
| CLAN-12 | PASS | Invitación privada genera solicitud pendiente desde UI | [Ver](evidence/CLAN-12.json) |
| ROUTE-01-D | PASS | Ruta /login · escritorio | [Ver](evidence/ROUTE-01-D.json) |
| ROUTE-02-D | PASS | Ruta / · escritorio | [Ver](evidence/ROUTE-02-D.json) |
| ROUTE-03-D | PASS | Ruta /home · escritorio | [Ver](evidence/ROUTE-03-D.json) |
| ROUTE-04-D | PASS | Ruta /design-system · escritorio | [Ver](evidence/ROUTE-04-D.json) |
| ROUTE-05-D | PASS | Ruta /missions · escritorio | [Ver](evidence/ROUTE-05-D.json) |
| ROUTE-06-D | PASS | Ruta /store · escritorio | [Ver](evidence/ROUTE-06-D.json) |
| ROUTE-07-D | PASS | Ruta /shop · escritorio | [Ver](evidence/ROUTE-07-D.json) |
| ROUTE-08-D | PASS | Ruta /feed · escritorio | [Ver](evidence/ROUTE-08-D.json) |
| ROUTE-09-D | PASS | Ruta /notifications · escritorio | [Ver](evidence/ROUTE-09-D.json) |
| ROUTE-10-D | PASS | Ruta /actions · escritorio | [Ver](evidence/ROUTE-10-D.json) |
| ROUTE-11-D | PASS | Ruta /actions/register · escritorio | [Ver](evidence/ROUTE-11-D.json) |
| ROUTE-12-D | PASS | Ruta /audit · escritorio | [Ver](evidence/ROUTE-12-D.json) |
| ROUTE-13-D | PASS | Ruta /clans · escritorio | [Ver](evidence/ROUTE-13-D.json) |
| ROUTE-14-D | PASS | Ruta /clans/:clanId · escritorio | [Ver](evidence/ROUTE-14-D.json) |
| ROUTE-15-D | PASS | Ruta /leaderboard · escritorio | [Ver](evidence/ROUTE-15-D.json) |
| ROUTE-16-D | PASS | Ruta /profile · escritorio | [Ver](evidence/ROUTE-16-D.json) |
| ROUTE-17-D | PASS | Ruta * · escritorio | [Ver](evidence/ROUTE-17-D.json) |
| ROUTE-01-M | PASS | Ruta /login · móvil | [Ver](evidence/ROUTE-01-M.json) |
| ROUTE-02-M | PASS | Ruta / · móvil | [Ver](evidence/ROUTE-02-M.json) |
| ROUTE-03-M | PASS | Ruta /home · móvil | [Ver](evidence/ROUTE-03-M.json) |
| ROUTE-04-M | PASS | Ruta /design-system · móvil | [Ver](evidence/ROUTE-04-M.json) |
| ROUTE-05-M | PASS | Ruta /missions · móvil | [Ver](evidence/ROUTE-05-M.json) |
| ROUTE-06-M | PASS | Ruta /store · móvil | [Ver](evidence/ROUTE-06-M.json) |
| ROUTE-07-M | PASS | Ruta /shop · móvil | [Ver](evidence/ROUTE-07-M.json) |
| ROUTE-08-M | PASS | Ruta /feed · móvil | [Ver](evidence/ROUTE-08-M.json) |
| ROUTE-09-M | PASS | Ruta /notifications · móvil | [Ver](evidence/ROUTE-09-M.json) |
| ROUTE-10-M | PASS | Ruta /actions · móvil | [Ver](evidence/ROUTE-10-M.json) |
| ROUTE-11-M | PASS | Ruta /actions/register · móvil | [Ver](evidence/ROUTE-11-M.json) |
| ROUTE-12-M | PASS | Ruta /audit · móvil | [Ver](evidence/ROUTE-12-M.json) |
| ROUTE-13-M | PASS | Ruta /clans · móvil | [Ver](evidence/ROUTE-13-M.json) |
| ROUTE-14-M | PASS | Ruta /clans/:clanId · móvil | [Ver](evidence/ROUTE-14-M.json) |
| ROUTE-15-M | PASS | Ruta /leaderboard · móvil | [Ver](evidence/ROUTE-15-M.json) |
| ROUTE-16-M | PASS | Ruta /profile · móvil | [Ver](evidence/ROUTE-16-M.json) |
| ROUTE-17-M | PASS | Ruta * · móvil | [Ver](evidence/ROUTE-17-M.json) |
| GUARD-02 | PASS | Sin sesión: / | [Ver](evidence/GUARD-02.json) |
| GUARD-03 | PASS | Sin sesión: /home | [Ver](evidence/GUARD-03.json) |
| GUARD-04 | PASS | Sin sesión: /design-system | [Ver](evidence/GUARD-04.json) |
| GUARD-05 | PASS | Sin sesión: /missions | [Ver](evidence/GUARD-05.json) |
| GUARD-06 | PASS | Sin sesión: /store | [Ver](evidence/GUARD-06.json) |
| GUARD-07 | PASS | Sin sesión: /shop | [Ver](evidence/GUARD-07.json) |
| GUARD-08 | PASS | Sin sesión: /feed | [Ver](evidence/GUARD-08.json) |
| GUARD-09 | PASS | Sin sesión: /notifications | [Ver](evidence/GUARD-09.json) |
| GUARD-10 | PASS | Sin sesión: /actions | [Ver](evidence/GUARD-10.json) |
| GUARD-11 | PASS | Sin sesión: /actions/register | [Ver](evidence/GUARD-11.json) |
| GUARD-12 | PASS | Sin sesión: /audit | [Ver](evidence/GUARD-12.json) |
| GUARD-13 | PASS | Sin sesión: /clans | [Ver](evidence/GUARD-13.json) |
| GUARD-14 | PASS | Sin sesión: /clans/:clanId | [Ver](evidence/GUARD-14.json) |
| GUARD-15 | PASS | Sin sesión: /leaderboard | [Ver](evidence/GUARD-15.json) |
| GUARD-16 | PASS | Sin sesión: /profile | [Ver](evidence/GUARD-16.json) |
| GUARD-17 | PASS | Sin sesión: * | [Ver](evidence/GUARD-17.json) |
| FE-TEST-001 | FAIL | should render sustainable action cards from the catalog endpoint | [Ver](evidence/frontend-tests.json) |
| FE-TEST-002 | FAIL | should show an error when the catalog endpoint fails | [Ver](evidence/frontend-tests.json) |
| FE-TEST-003 | FAIL | should show an error when the catalog payload is malformed | [Ver](evidence/frontend-tests.json) |
| FE-TEST-004 | FAIL | should load catalog cards after retry reaches a valid response | [Ver](evidence/frontend-tests.json) |
| FE-TEST-005 | FAIL | should require an action before submitting the registration form | [Ver](evidence/frontend-tests.json) |
| FE-TEST-006 | FAIL | should reject photographic evidence larger than 5MB | [Ver](evidence/frontend-tests.json) |
| FE-TEST-007 | FAIL | should require a photo when the selected action uses PHOTO validation | [Ver](evidence/frontend-tests.json) |
| FE-TEST-008 | FAIL | should show an error when the catalog GET fails | [Ver](evidence/frontend-tests.json) |
| FE-TEST-009 | PASS | should list pending evidence with approve and reject controls | [Ver](evidence/frontend-tests.json) |
| FE-TEST-010 | PASS | should show an error when the audit queue GET fails | [Ver](evidence/frontend-tests.json) |
| FE-TEST-011 | PASS | should require a rejection reason before rejecting evidence | [Ver](evidence/frontend-tests.json) |
| FE-TEST-012 | PASS | should remove an item after a successful approve request | [Ver](evidence/frontend-tests.json) |
| FE-TEST-013 | PASS | should switch to the campaign proposals tab and reflect it in the URL | [Ver](evidence/frontend-tests.json) |
| FE-TEST-014 | PASS | should open the proposals tab directly from ?tab=propuestas | [Ver](evidence/frontend-tests.json) |
| FE-TEST-015 | PASS | should list campaigns and open the detail of one | [Ver](evidence/frontend-tests.json) |
| FE-TEST-016 | PASS | should filter campaigns by status and scope | [Ver](evidence/frontend-tests.json) |
| FE-TEST-017 | PASS | should join a campaign in promotion | [Ver](evidence/frontend-tests.json) |
| FE-TEST-018 | PASS | should show the progress of their missions in the dashboard | [Ver](evidence/frontend-tests.json) |
| FE-TEST-019 | PASS | should propose a campaign and list it as pending | [Ver](evidence/frontend-tests.json) |
| FE-TEST-020 | PASS | should create a private campaign for a clan | [Ver](evidence/frontend-tests.json) |
| FE-TEST-021 | PASS | should show the backend error when the user does not lead the clan | [Ver](evidence/frontend-tests.json) |
| FE-TEST-022 | PASS | should create a global campaign with a mission | [Ver](evidence/frontend-tests.json) |
| FE-TEST-023 | PASS | should approve a pending proposal | [Ver](evidence/frontend-tests.json) |
| FE-TEST-024 | PASS | should reject a pending proposal with a reason | [Ver](evidence/frontend-tests.json) |
| FE-TEST-025 | PASS | should edit a campaign in promotion | [Ver](evidence/frontend-tests.json) |
| FE-TEST-026 | PASS | should not offer editing once the campaign left promotion | [Ver](evidence/frontend-tests.json) |
| FE-TEST-027 | PASS | should not let an admin join a campaign | [Ver](evidence/frontend-tests.json) |
| FE-TEST-028 | PASS | should show an error and recover on retry when campaigns fail to load | [Ver](evidence/frontend-tests.json) |
| FE-TEST-029 | PASS | should show the empty state when there are no campaigns | [Ver](evidence/frontend-tests.json) |
| FE-TEST-030 | PASS | should show the empty states of the dashboard when the user has no campaigns | [Ver](evidence/frontend-tests.json) |
| FE-TEST-031 | PASS | should show an error when the campaign detail fails to load | [Ver](evidence/frontend-tests.json) |
| FE-TEST-032 | PASS | should show an error when joining fails | [Ver](evidence/frontend-tests.json) |
| FE-TEST-033 | PASS | should validate the required fields of the campaign form | [Ver](evidence/frontend-tests.json) |
| FE-TEST-034 | PASS | should show the empty state when there are no pending proposals | [Ver](evidence/frontend-tests.json) |
| FE-TEST-035 | PASS | should show an error when proposals fail to load | [Ver](evidence/frontend-tests.json) |
| FE-TEST-036 | PASS | should show an error when approving a proposal fails | [Ver](evidence/frontend-tests.json) |
| FE-TEST-037 | PASS | should list clans and filter them with the search box | [Ver](evidence/frontend-tests.json) |
| FE-TEST-038 | PASS | should show an empty state when the search has no results | [Ver](evidence/frontend-tests.json) |
| FE-TEST-039 | PASS | should show an error with retry when the clan list fails | [Ver](evidence/frontend-tests.json) |
| FE-TEST-040 | PASS | should show the clan profile with its members and member actions | [Ver](evidence/frontend-tests.json) |
| FE-TEST-041 | PASS | should set the clan as active | [Ver](evidence/frontend-tests.json) |
| FE-TEST-042 | PASS | should leave a clan after confirming and go back to the list | [Ver](evidence/frontend-tests.json) |
| FE-TEST-043 | PASS | should show leader actions and transfer leadership | [Ver](evidence/frontend-tests.json) |
| FE-TEST-044 | PASS | should dissolve the clan after confirming | [Ver](evidence/frontend-tests.json) |
| FE-TEST-045 | PASS | should create a clan and open its profile | [Ver](evidence/frontend-tests.json) |
| FE-TEST-046 | PASS | should translate a duplicate clan name error | [Ver](evidence/frontend-tests.json) |
| FE-TEST-047 | PASS | should require a name before creating a clan | [Ver](evidence/frontend-tests.json) |
| FE-TEST-048 | PASS | should join a public clan from its profile | [Ver](evidence/frontend-tests.json) |
| FE-TEST-049 | PASS | should request to join an invite-only clan from an invite link | [Ver](evidence/frontend-tests.json) |
| FE-TEST-050 | PASS | should reject an invite link without a clan id | [Ver](evidence/frontend-tests.json) |
| FE-TEST-051 | PASS | should show the clans link in the sidebar navigation | [Ver](evidence/frontend-tests.json) |
| FE-TEST-052 | PASS | should not show the leave notice again after reloading the list | [Ver](evidence/frontend-tests.json) |
| FE-TEST-053 | PASS | should send a single create request when submit is double clicked | [Ver](evidence/frontend-tests.json) |
| FE-TEST-054 | PASS | should keep the profile when a background refresh fails | [Ver](evidence/frontend-tests.json) |
| FE-TEST-055 | PASS | should not reload the clan when copying the invite link | [Ver](evidence/frontend-tests.json) |
| FE-TEST-056 | PASS | should keep the confirm dialog open while the request is in flight | [Ver](evidence/frontend-tests.json) |
| FE-TEST-057 | FAIL | should display welcome message | [Ver](evidence/frontend-tests.json) |
| FE-TEST-058 | FAIL | should display tech stack | [Ver](evidence/frontend-tests.json) |
| FE-TEST-059 | PASS | should show the global ranking table by default | [Ver](evidence/frontend-tests.json) |
| FE-TEST-060 | PASS | should load the institutional clan ranking from GET /rankings/?type= | [Ver](evidence/frontend-tests.json) |
| FE-TEST-061 | PASS | should load private clan ranking rows using clan_name | [Ver](evidence/frontend-tests.json) |
| FE-TEST-062 | PASS | should request the next rankings page with limit and offset | [Ver](evidence/frontend-tests.json) |
| FE-TEST-063 | PASS | should return to the first page when the ranking count no longer fills page two | [Ver](evidence/frontend-tests.json) |
| FE-TEST-064 | PASS | should show an error when the global ranking GET fails | [Ver](evidence/frontend-tests.json) |
| FE-TEST-065 | PASS | should render the Microsoft login screen | [Ver](evidence/frontend-tests.json) |
| FE-TEST-066 | PASS | should redirect unauthenticated users to /login | [Ver](evidence/frontend-tests.json) |
| FE-TEST-067 | PASS | should display full ecological profile with all sections and metrics | [Ver](evidence/frontend-tests.json) |
| FE-TEST-068 | PASS | should gracefully handle empty states for badges, clans, and campaigns | [Ver](evidence/frontend-tests.json) |
| FE-TEST-069 | PASS | should show error banner when profile request fails and recover on retry | [Ver](evidence/frontend-tests.json) |
| FE-TEST-070 | PASS | should navigate back to home using the back button | [Ver](evidence/frontend-tests.json) |
| FE-TEST-071 | PASS | should navigate to profile from the navbar user dropdown | [Ver](evidence/frontend-tests.json) |
| FE-TEST-072 | PASS | should redirect unauthenticated users from /audit to /login | [Ver](evidence/frontend-tests.json) |
| FE-TEST-073 | PASS | should block STUDENT from accessing /audit and show 403 Access Denied | [Ver](evidence/frontend-tests.json) |
| FE-TEST-074 | PASS | should block STAFF from accessing /audit and show 403 Access Denied | [Ver](evidence/frontend-tests.json) |
| FE-TEST-075 | PASS | should grant ADMIN access to /audit review panel | [Ver](evidence/frontend-tests.json) |
| FE-TEST-076 | PASS | should allow STUDENT to access standard protected routes like /actions | [Ver](evidence/frontend-tests.json) |
| FE-TEST-077 | PASS | should allow STAFF to access standard protected routes like /actions | [Ver](evidence/frontend-tests.json) |
| FE-TEST-078 | PASS | should not render admin UI controls on Home for STUDENT users | [Ver](evidence/frontend-tests.json) |
| FE-TEST-079 | PASS | should not render admin UI controls on Home for STAFF users | [Ver](evidence/frontend-tests.json) |
| FE-TEST-080 | FAIL | should conditionally render admin UI controls exclusively for ADMIN users | [Ver](evidence/frontend-tests.json) |
| BE-SUITE | PASS | Suite completa del backend | [Ver](logs/backend-tests.log) |
| FE-BUILD | PASS | Compilación de producción del frontend | [Ver](build-result.json) |
| GAP-01 | NOT RUN | Login institucional en la revisión actual | Pendiente |
| GAP-02 | NOT RUN | Despliegue compartido y migraciones del release | Pendiente |
| GAP-03 | NOT RUN | Carga real de fotografía a almacenamiento | Pendiente |
| GAP-04 | NOT RUN | Registro por QR dinámico | Pendiente |
| GAP-05 | NOT RUN | Instalación PWA y funcionamiento del shell offline | Pendiente |
| GAP-06 | NOT RUN | Safari/Firefox y dispositivos físicos | Pendiente |
| GAP-07 | NOT RUN | Rendimiento P95 y carga del sistema | Pendiente |
| GAP-08 | NOT RUN | Accesibilidad completa y navegación por teclado | Pendiente |
| GAP-09 | NOT RUN | Avatar de clan y expulsión/gestión de solicitudes desde UI | Pendiente |
| GAP-10 | NOT RUN | Todas las variantes cosméticas/equipamiento de la tienda | Pendiente |
| GAP-11 | NOT RUN | Alta institucional de una cuenta nueva / onboarding Microsoft | Pendiente |
| GAP-12 | NOT RUN | Bloqueo/desbloqueo y panel completo de usuarios | Pendiente |
| GAP-13 | NOT RUN | Dashboard de impacto de todo el campus | Pendiente |

## Trazabilidad de requisitos

| Requisito | Cobertura | Casos |
|---|---|---|
| FR-AUTH-01 · Autenticación Institucional | PARTIAL | QA35A, GAP-01, GAP-11 |
| FR-AUTH-02 · Perfil Ecológico | GAPS FOUND | QA10C, QA11A, GAP-13 |
| FR-AUTH-03 · Gestión de Roles Globales vs. Contextuales | PARTIAL | QA29D, QA29E, QA29G, GAP-12 |
| FR-CLAN-01 · Clanes Institucionales / Facciones | PARTIAL | QA30A, QA30B, GAP-11 |
| FR-CLAN-02 · Creación de Clanes Privados | PARTIAL | CLAN-02, QA36B, GAP-09 |
| FR-CLAN-03 · Administración de Miembros y Borrado Lógico | PARTIAL | CLAN-05, CLAN-06, CLAN-08, CLAN-09, QA36E, GAP-09 |
| FR-ACT-01 · Catálogo Maestro de Acciones | GAPS FOUND | QA12A, QA38A, QA38B |
| FR-ACT-02 · Reglas Anti-Fraude por Frecuencia | PARTIAL | QA25C, BE-SUITE |
| FR-VAL-01 · Registro Libre y Hábitos Diarios | GAPS FOUND | QA04 |
| FR-VAL-02 · Registro con Foto Evidencia y Auditoría de Rechazo | GAPS FOUND | QA06C, GAP-03 |
| FR-VAL-03 · Registro por Código QR Dinámico | PARTIAL | GAP-04 |
| FR-GAM-01 · Motor de Acreditación y Reversión de Puntos | PASS | QA05A, QA06D, QA06E |
| FR-GAM-02 · Tablas de Rankings / Leaderboards | PASS | QA08A, QA08B |
| FR-GAM-03 · Badges e Insignias | GAPS FOUND | QA10C |
| FR-CAMP-01 · Estructuración de Misiones | PASS | QA26A, QA31D |
| FR-CAMP-02 · Campañas Globales | PASS | QA26A, QA26B |
| FR-CAMP-03 · Propuestas de Campañas Globales | PASS | QA27A, QA27B, QA27E, QA27F |
| FR-CAMP-04 · Campañas Privadas / de Clan | PASS | QA31A, QA31B |
| FR-CAMP-05 · Ciclo de Vida Automático | PARTIAL | BE-SUITE |
| FR-COMM-01 · Feed Social Dinámico | PARTIAL | FEED-01, FEED-02, FEED-03 |
| FR-DASH-01 · Dashboard Resumen del Usuario | PARTIAL | ROUTE-02-D |
| FR-DASH-02 · Dashboard ITESO Impact | PARTIAL | GAP-13 |
| FR-DASH-03 · Panel de Administración y Moderación | GAPS FOUND | QA27B, QA27E, QA06C, GAP-12 |
| NFR-STACK-01 · Backend Python / Django | PASS | BE-SUITE |
| NFR-STACK-02 · Frontend React / Vite SPA | PASS | FE-BUILD |
| NFR-PWA-01 · PWA Mobile-First & Alcance Conectado | PARTIAL | GAP-05, GAP-06 |
| NFR-SEC-01 · Seguridad y Autenticación | PARTIAL | GAP-02, QA35A |
| NFR-SEC-02 · Control de Acceso RBAC | PASS | QA29D, QA29G, GUARD-12 |
| NFR-PERF-01 · Rendimiento de APIs | PARTIAL | GAP-07 |
| NFR-RELI-01 · Consistencia Transaccional | PARTIAL | BE-SUITE |
| NFR-ARCH-01 · Integración de Módulos | PARTIAL | GAP-02 |

## PRs abiertos fuera de esta versión

- [Frontend #44 · feat: dashboard impact totals](https://github.com/GreenITESO-Proyecto-Integrador/GreenITESO-Frontend/pull/44)
- [Frontend #42 · feat: profile editing](https://github.com/GreenITESO-Proyecto-Integrador/GreenITESO-Frontend/pull/42)
- [Frontend #37 · feat(notifications): wire real time notifications to the backend](https://github.com/GreenITESO-Proyecto-Integrador/GreenITESO-Frontend/pull/37)
- [Backend #146 · feat(accounts): add ecological profile metrics endpoint](https://github.com/GreenITESO-Proyecto-Integrador/GreenITESO-Backend/pull/146)
- [Backend #143 · feat(accounts): add weekly impact-trend endpoint for the dashboard](https://github.com/GreenITESO-Proyecto-Integrador/GreenITESO-Backend/pull/143)
- [Backend #30 · feat: migraciones antes del despliegue por digest](https://github.com/GreenITESO-Proyecto-Integrador/GreenITESO-Backend/pull/30)

## Diferencias que deben aclararse en la especificación

La SRS general describe acreditación inmediata con foto; la API integrada observada usa PENDING_AUDIT sin puntos hasta aprobar. La política específica P10 del backend usa el día de calendario America/Mexico_City y cuenta también registros rechazados; la SRS general menciona 24 horas/límite semanal. Se documenta el comportamiento probado, sin resolver por cuenta propia esos contratos.