--- asset_id: MIN-EL-Gustavo-20260701-v01 tipo: MIN — Minuta del día owner: Gustavo sherpa: GusX ratificador: Gustavo fecha: 2026-07-01 intellibank: IB-EL-EmpowerLabs subbank: EQ-EL-Equipo proyecto: RCH — Rebelocity Club · directorio (tab Atletas / Coaches / Clubs) --- ## Qué se hizo ### Revisión de pendientes registrados en memoria - Verificado `admin.php`: los 5 cambios pendientes de `fecha_nacimiento` en `perfil_extra_data` (extracción, UPDATE, INSERT, `$queryParams`, SELECT) **ya estaban aplicados** en el archivo actual. Pendiente cerrado, memoria actualizada. - Referencia del mockup del Directorio (`SPEC-RCH-Directorio-v01.md`) confirmada, sin cambios. --- ### Análisis de validaciones — tab Atletas y Coaches (`getListAtletas` / `getListCoaches`) Auditoría de archivos (`general.php` en `api_rch/controllers/rebelocity/`, `admin.php`, `index.php`, `athlete.service.ts`, `athlete-directory.component.ts`): - Documentadas las tablas/condiciones de ambos endpoints: `colaborador` (`origen=169`) → `perfil` (JOIN por `wikiname`) → `perfil_extra_data` (JOIN por `email`, `visible_directorio=1`; Coaches agrega `rol='coach'`). - Confirmado: no hay autenticación/sesión en ninguna ruta de `api_rch` (solo CORS por origin, no es auth). - Confirmado: filtros y paginación del directorio son 100% client-side; el backend no los recibe. Detectado método muerto `AthleteService.getAthletes()` que apunta a una ruta `/directorio/miembros` inexistente en `index.php`. --- ### Bug encontrado — Coach no aparecía en el directorio **Causa identificada (case-sensitivity):** `general.php:197` filtra `ped.rol = 'coach'` (minúscula exacta), pero el dropdown `roles` en `perfil-usuario.component.ts:225-230` guarda el valor con mayúscula inicial (`"Coach"`), y `admin.php` lo persiste tal cual sin normalizar. **No se aplicó fix** — decisión explícita del usuario de no modificar por ahora para evitar romper otros flujos (ver Decisiones). **Segundo bug real, distinto — encontrado y resuelto hoy:** la pestaña Coaches no devolvía ningún dato en absoluto (ni con el bug de arriba de por medio). Diagnóstico paso a paso: 1. Confirmado con `console.log` en `getCoaches()` (`athlete-directory.component.ts`) que la función se ejecutaba pero la respuesta nunca llegaba a `next`. 2. Agregado log al callback `error` → reveló `HttpErrorResponse 404` contra `https://genniux.net/api_rch/rch/rebelocity/directorio/coaches`, body `{"message":"Not found"}` (404 nativo de Slim, ruta no registrada). 3. Auditoría de `git log` en `/home/gus/Trabajo/Volume/archivos-server/` (sin remoto configurado → despliegue es manual, no vía `git push`): la ruta `/directorio/coaches` se agregó en el commit más reciente (`d1d3375 "aupds"`), posterior al despliegue vigente en producción. La ruta `/directorio/atletas` (que sí funcionaba) venía de un commit anterior ya desplegado. 4. **Causa raíz: gap de despliegue**, no de código — `index.php`/`general.php` en `genniux.net` no tenían aún la ruta ni la función `getListCoaches()`. 5. Usuario desplegó los archivos actualizados → confirmado que los datos llegan correctamente al frontend (console.log de respuesta poblado). **Tercer hallazgo — no era bug:** tras el despliegue, los datos llegaban pero la tarjeta no se pintaba en pantalla. Causa: el filtro client-side `coachFilters.disponible = true` (chip "Disponibles", activo por defecto) descarta en `filterCoaches()` cualquier coach con `acepta_atletas` falsy. El coach de prueba no tenía ese campo activo. **Confirmado con el usuario que es comportamiento esperado** (se verificó desactivando el chip en la UI y la tarjeta apareció) — no requiere cambio. --- ### Tab Clubs — alineación con el mockup del Directorio **Contexto:** se comparó tarjeta, modal y filtros del tab Clubs (`club-card`, `club-profile-modal`, `athlete-directory` sección clubes) contra `SPEC-RCH-Directorio-v01.md`. El tab se había implementado antes de que existiera el spec y difería en varios puntos. **Hallazgos previos a implementar:** - El backend (`listClubs()`, `general.php:562`) ya devolvía `disciplinas` (JSON array de la columna `disciplines`) pero el frontend (`Club` model, card, modal, filtros) lo ignoraba por completo. - No existe columna de capacidad/cupo en `clubs` (confirmado con el `CREATE TABLE` real compartido por el usuario) ni campo en el formulario de registro de club — el badge de admisión del mockup ("✓ Admite miembros" / "Cupo completo") no tenía con qué calcularse. - El filtro `tipo_club` (Triatlón/Ciclismo) y el filtro de `ciudad` no están contemplados en el mockup (que solo pide Disciplina + País + Admisión). - El avatar de club mostraba iniciales sobre color sólido; el mockup pide un emoji en círculo `--card2`, sin gradiente — pero el HTML real del mockup no estaba disponible (solo quedó un placeholder de 1 línea), así que no había forma de saber el emoji exacto usado. **Decisiones tomadas con el usuario antes de implementar:** 1. **Admisión/cupo:** hardcodear temporalmente `admision: 'open'` en el backend para todos los clubes, en vez de construir el campo real en BD + formulario de registro (proceso extenso que el usuario decidió posponer). El frontend queda armado con la lógica binaria del badge (`open`/`full`) del mockup desde ahora; cuando exista la columna real, solo cambia el origen del dato en el backend, sin tocar frontend. 2. **Filtro tipo_club → disciplina:** reemplazado por fidelidad al mockup, reusando el array `disciplinas` ya disponible. 3. **Filtro ciudad:** eliminado, no está en el mockup. 4. **Emoji del avatar:** mapeado por disciplina principal del club (🏆 triatlón, 🏃 running, 🚴 ciclismo, 🏊 natación, ⚡ multi-sport, 👥 si no hay disciplina), en vez de un emoji fijo único o mantener las iniciales — decisión del usuario pese a no tener el mockup real como referencia exacta. **Implementación (plan ejecutado vía Plan Mode, aprobado por el usuario):** - Backend `general.php`, `listClubs()`: agregado `'admision' => 'open'` con comentario `TODO` de hardcode temporal. - `Club.ts`: nuevos campos `disciplinas?: string[]`, `admision?: 'open' | 'full'`. - `club.service.ts`: `ClubFilters` — quitado `tipo_club`/`ciudad`, agregado `disciplina`/`admision`. - `athlete-directory.component.ts`: `clubFilters` actualizado, `tipoClubOpts` eliminado (reusa `disciplinaOpts` existente), `filterClubs()` filtra por `disciplinas` (mismo patrón `normalize()` que Atletas/Coaches) y por `admision`, nuevo método `toggleClubAdmision()`, `onClubCiudadChange()` eliminado. - `athlete-directory.component.html`: fila de filtros de Clubs con `ms-select` de Disciplina (idéntico a Atletas/Coaches) + País + 3 chips de Admisión (Todos / Admite miembros / Cupo completo). - `club-card` (ts/html/less): avatar emoji reemplaza iniciales, orden de info corregido a "N miembros" → "Ciudad, País" (antes invertido), badge de admisión (verde/gris), chips de disciplinas reales reemplazan el chip fijo "Club" + `tipoLabel`, línea "Capitán" removida de la tarjeta (se mantiene en el modal). - `club-profile-modal` (ts/html/less): mismos cambios de fondo — emoji, badge de admisión, sección nueva de chips "Disciplinas" siguiendo el mismo patrón que `athlete-profile-modal`. - Verificado con `npx tsc --noEmit` y `ng build --configuration=production` (exit 0, sin errores en archivos tocados). Confirmado visualmente correcto por el usuario en navegador. --- ### Modal de Coach — análisis y reconstrucción completa **Punto de partida:** el modal que se abre al hacer clic en una tarjeta de Coach es el mismo componente compartido con Atletas (`app-athlete-profile-modal`), pero mostraba datos con el layout de Atleta (género/edad, sin especialidad). **Bug encontrado de paso:** `onCoachCardClick()` guardaba el coach en `this.selectedCoach`, pero el template del modal estaba bindeado a `[athlete]="selectedAthlete"` — **nunca leía `selectedCoach`**. El modal de coach nunca mostró el dato correcto. Se corrigió unificando a una sola variable `selectedAthlete` + nueva propiedad `modalMode: 'atleta' | 'coach'`. **Proceso de validación con el usuario:** se armó una tabla comparativa spec-vs-implementación basada en capturas reales del mockup (tarjeta de Coach + 4 variantes del modal de Coach compartidas por el usuario), no solo en el `.md` del spec (que no documenta modales). Se detectó que el mockup real: - Muestra "Coach · XX años" (rol+edad) en vez de género+edad. - Tiene secciones condicionales según haya dato: Biografía, badge de contacto (Strava/Instagram). - Usa "Experiencia" (mismo dato que `nivel`) en vez de "Nivel". - Tiene una sección "Me especializo en" (especialidad) que no existía en el modal. - "Club/Equipo" siempre se muestra con fallback "Ninguno" en vez de ocultarse si está vacío. **Backend (`getListCoaches()`):** agregado `p.bio` y `ped.evento_objetivo` al SELECT (no se seleccionaban); agregado `biografia`, `eventos_objetivo`, `link_strava`, `link_instagram` al array de salida (estos 2 últimos ya se seleccionaban pero nunca se devolvían). **Frontend (`athlete-profile-modal`):** se agregó `@Input() mode` y se dividió el template en dos bloques completos (coach / atleta) vía `*ngIf...else` con `ng-template`, sin tocar el bloque de Atleta existente. Nuevo bloque de Coach: Biografía → Disciplina(s) con ícono → Experiencia → Evento objetivo 2026 → Club/Equipo (con "Ninguno") → Me especializo en → Disponibilidad (badge verde/gris). --- ### Homologación visual de las 3 tarjetas (Atletas / Coaches / Clubs) **Contexto:** las 3 tarjetas del directorio se veían visiblemente distintas entre sí (altura, fondo, tipografía, borde de avatar, tamaño de avatar). Se usó `club-card` como referencia visual por decisión del usuario ("se ve mejor"), con ajustes de dirección en 2 puntos donde el usuario corrigió mi lectura inicial. **Iteración 1 — cambios directos:** - Altura: unificada a un valor fijo (inicialmente 360px, tomando el que ya usaba Clubs). - Fondo: `#ffffff` → `#f0f0f0` en Atletas/Coaches (antes solo lo tenía Clubs), con el mismo hover a blanco. - Tipografía (parcial): tamaño/color del nombre y texto de datos igualados. - Borde del avatar: `3px solid #fff` + sombra agregado a Atletas/Coaches (ya lo tenía Clubs). **Corrección del usuario — dirección invertida en 2 puntos:** 1. **Tamaño de avatar:** en vez de agrandar Atletas/Coaches a 110px (mi sugerencia inicial), el usuario pidió **achicar el de Clubs a 76px** para igualar a Atletas/Coaches. 2. **Alineación vertical del contenido:** el usuario corrigió que el patrón correcto es el de Atletas/Coaches (contenido anclado arriba, footer con `margin-top:auto` empujado al fondo) — esto evita que los avatares se desalineen entre tarjetas con distinta cantidad de contenido. **Clubs era el que estaba mal** con `justify-content:center`. Se restructuró `club-card` (HTML + LESS) para adoptar el mismo patrón: se quitó `justify-content:center`, se sacó el wrapper `&__info`, se agregó `&__footer` con `margin-top:auto` conteniendo badge+chips, igual que Atletas/Coaches. **Simulación de altura (a pedido explícito del usuario, antes de tocar código):** se calculó a mano el alto de cada tarjeta con TODOS sus elementos opcionales activos a la vez (padding + gaps + altura de línea de texto + badges/chips), usando los valores reales de cada `.less`: - Atleta (máx: 2 badges + meta 2 líneas + chips disciplina): **249px** - Coach (máx: badge + label especialidad + chips): **253px** - Club (máx: 2 líneas detalle + badge + chips): **259px** ← el mayor - Alto aplicado: **280px** (259px + colchón de seguridad) en las 3 tarjetas y en sus skeletons de carga (`athlete-list`, `club-list`), reemplazando los 360px iniciales que dejaban demasiado espacio vacío. **Iteración 2 — fuente del nombre (persistía diferencia pese a tamaño/color iguales):** - Causa real: `.athlete-card__name` tenía `font-family: 'Montserrat'` forzado; `.club-card__name` no declara `font-family` propio y hereda la variable global `--main-font` (`'Raleway'`, definida en `styles.less:9`). Se quitó el override de Montserrat en Atletas/Coaches para que ambas hereden la misma fuente global. - Se auditó exhaustivamente (`grep` en todo `src/`) que no existe ninguna otra definición de `athlete-card__name` ni `club-card__name` en el proyecto, ni overrides vía `::ng-deep` desde `athlete-directory.component.less` ni desde los componentes `-list` padres — se descartó cualquier conflicto de cascada CSS. **Iteración 3 — badge de estado (no es lo mismo que "chips" de disciplina/especialidad):** - `font-weight`: Atleta/Coach usaba `700`, Club usa `600` → igualado a `600`. - Verde del badge positivo: Atleta/Coach usaba `rgba(5,150,105,...)`, Club usa `rgba(16,185,129,...)` → igualado (incluso con el mismo color de texto `#059669`, el tono de fondo/borde traslúcido era distinto). **Iteración 4 — refactor de marcado (mejora de mantenibilidad pedida explícitamente):** - `athlete-card__meta` usaba una sola `
` con hasta 7 `` condicionales + un `
` para separar "género · edad" de "ciudad, país" — dificultaba modificar el texto de cada línea por separado. - Reestructurado a **dos `

`** (una por línea de dato), replicando el mismo patrón que ya usa `club-card__detail` (párrafo por línea + un solo `` de separador). La clase ya tenía el `margin:0` necesario para un `

`. --- ### Integración del mockup real completo (v01 → v02) — corrige supuestos hechos solo con el `.md` **Contexto:** el usuario compartió los 2 archivos HTML/CSS/JS reales del mockup (`MOCKUP-RCH-Directorio-v01.html` y `v02.html`), algo que no se tenía disponible en sesiones anteriores (solo existía el placeholder de 1 línea + el `.md` de spec, que no documenta modales). Se pidió analizar a profundidad el diff v01→v02 y reportar cambios por apartado antes de tocar código. **Hallazgos del diff v01 vs v02:** - Sistema de íconos: emoji de texto → `Material Symbols Rounded` (transversal a las 3 tarjetas, 3 modales y filtros). **Pospuesto a backlog (B08)**. - 🔴 v02 **elimina el toggle "Disponibles/Ver todos" y el badge de disponibilidad de Coach** — los no disponibles quedan excluidos siempre (`if (avail === 'no') matchFilters = false;`, sin opción de verlos). Contradice directamente el trabajo de la sesión anterior. - 🔴 v02 **elimina los 3 chips de Admisión y el badge de Club** — mismo patrón, clubes con cupo completo excluidos siempre. - v02 agrega Biografía + contacto social (Strava/Instagram) **también a Atletas**, no exclusivo de Coach como se había asumido. - v02 **elimina el badge "Busco coach"** de atletas (tarjeta y modal). - v02 agrega relay con 3 estados (buscando/completo/reemplazo) — no existe en el modelo de datos actual. **Pospuesto a backlog (B06)**. - v02 agrega campo "Coach responsable" en el modal de Club — no existe en la tabla `clubs`. **Pospuesto a backlog (B07)**. - v02 confirma que el subtítulo del modal es **"{Rol} · edad"** (nunca género) para ambos roles — hallazgo adicional detectado al implementar bio+social, no estaba en el diff inicial reportado. **Decisiones del usuario:** seguir v02 en las 2 reversiones (disponibilidad Coach, admisión Club) — se prioriza fidelidad al mockup real sobre el trabajo ya invertido. Bio+social en Atletas se implementa ya (bajo esfuerzo, dato ya disponible en backend). Relay 3 estados, Coach responsable y Material Symbols quedan en backlog por requerir modelo de datos nuevo o ser cambio de infraestructura transversal. **Implementación:** - Backend: `getListCoaches()` agrega `AND ped.acepta_atletas = 1` al WHERE (exclusión permanente); `listClubs()` quita por completo el campo `admision` (no solo el hardcode — la feature entera se eliminó); `getListAtletas()` agrega `biografia`, `link_strava`, `link_instagram` al output. - Frontend: eliminados en su totalidad — filtro+badge de disponibilidad de Coach (`CoachFilters.disponible`, `toggleCoachDisponible()`, `@Input() acepta_atletas`, CSS asociado) y filtro+badge de admisión de Club (`ClubFilters.admision`, `Club.admision`, `toggleClubAdmision()`, CSS asociado). Eliminado badge "Busco coach" de Atleta (`@Input() busco_coach`). - **Modal unificado:** `athlete-profile-modal` pasó de 2 bloques casi duplicados (`*ngIf mode==='coach' else atletaRight` con `ng-template`) a **un solo bloque compartido** con diferencias puntuales inline (`{{ mode === 'coach' ? 'Experiencia' : 'Nivel' }}`, sección "Me especializo en" solo si `mode==='coach'`) — reduce duplicación de código real, no solo visual. - Verificado con `ng build --configuration=production` (exit 0) y `grep` en todo `src/` para confirmar cero referencias huérfanas a `admision`/`disponible` tras el borrado. --- ## Decisiones - **No tocar la base de datos local bajo ninguna circunstancia** (ni siquiera en modo solo-lectura para diagnóstico) — el docker local (`genniux_server`) no está sincronizado con los datos reales y genera diagnósticos falsos. Regla guardada en memoria (`feedback_no_local_db_access`). Toda depuración de backend debe hacerse por análisis estático de archivos únicamente. - **Bug `ped.rol = 'coach'` (case-sensitive) queda documentado pero sin resolver**, por decisión explícita del usuario. Se planteó ampliar el fix a normalización canónica (minúscula al guardar + formato al mostrar) para los demás dropdowns del perfil (`generos`, `disciplinas`, `relayDisciplinas`, `relayCarreras`, `niveles`, `especialidades`), pero se identificaron dos bloqueos reales sin resolver antes de tocar código: 1. `eventosObjetivo` y `relayCarreras` tienen nombres de marca/propios (`IRONMAN`, `Encarnación`) que una transformación `lowercase + ucfirst` rompe (pierde mayúsculas de marca). 2. Migración de datos ya guardados en Title Case en `perfil_extra_data` — no decidido si migrar con `UPDATE` o tolerar formato mixto. Usuario decidió **no modificar nada por ahora** para no arriesgar romper flujos existentes. Queda como pendiente abierto (ver backlog B04). - Confirmado el patrón de despliegue del backend RCH: git local sin remoto → subida manual a `genniux.net`. Al agregar rutas/funciones nuevas, verificar que efectivamente se suban antes de dar por cerrado un feature. - **Admisión/cupo de Clubs — reversión completa:** el hardcode `admision: 'open'` (y todo el badge/filtro asociado) se **eliminó por completo** al integrar el mockup real v02, que quita esa feature de la UI en vez de mantenerla. B05 queda obsoleto (ver tabla de obsoletos en el backlog) — no hay nada que migrar a columna real porque la feature ya no existe. - **Disponibilidad de Coach — misma reversión:** el badge "Acepta atletas/No disponible" y el toggle "Disponibles/Ver todos" también se eliminaron siguiendo v02; el filtro ahora excluye siempre a los no disponibles directamente en el backend (`WHERE ped.acepta_atletas = 1`). B03 queda obsoleto por el mismo motivo. - **El mockup HTML/CSS/JS real siempre gana sobre el `.md` de spec o sobre trabajo ya implementado** — cuando hay conflicto entre lo ya construido y lo que dice el mockup real, se sigue el mockup real, incluso si implica revertir trabajo reciente. - **Emoji de club:** se mapea por disciplina principal en vez de usar un emoji fijo o mantener iniciales, pese a no contar con el HTML real del mockup como referencia exacta — el usuario prefirió la opción más expresiva visualmente. - **Referencia visual de homologación de tarjetas: Atletas/Coaches, no Clubs**, en los 2 puntos donde hubo ambigüedad — tamaño de avatar (76px, no 110px) y alineación de contenido (anclado arriba + footer al fondo, no centrado). Razón del usuario: centrar como bloque desalinea avatares entre tarjetas con distinta cantidad de contenido; anclar arriba no. Aplica como criterio general para futuras homologaciones entre estos 3 tipos de tarjeta. - **Altura de tarjetas del directorio calculada por simulación manual**, no por ensayo visual — sumando padding+gaps+línea de texto+badges de cada `.less` real, tomando el máximo entre los 3 tipos de tarjeta con todos sus elementos opcionales activos a la vez, más un colchón de seguridad. Metodología reutilizable si se agregan más campos a futuro a cualquiera de las 3 tarjetas. - **Modal de Coach:** el `.md` del spec no documenta modales (solo tarjetas/filtros) — para reconstruirlo se necesitaron capturas reales del mockup, no bastó con el markdown. A futuro, pedir el mockup HTML/imágenes completas antes de asumir que el `.md` es la fuente de verdad total. --- ### B08 — Migración de íconos emoji a Material Symbols Rounded **Implementación:** - `index.html`: agregada la fuente `Material Symbols Rounded` (Google Fonts). - `styles.less`: nueva clase utilitaria global `.ms` (+ variantes `.sm`/`.xs`/`.xxs`), igual a la definición del mockup. - `club-card` + `club-profile-modal`: emoji de disciplina (🏆🏃🚴🏊⚡👥) → íconos reales (`pool`, `directions_bike`, `directions_run`, `sports`, `groups`); Triatlón combina los 3 íconos con `gap:2px`, igual que el mockup. - `athlete-card`: badge "🤝 Busco equipo" → ícono `handshake`. - `athlete-profile-modal`: íconos de disciplina en modo Coach migrados al mismo esquema. - Los íconos de contacto (Strava/Instagram) ya usaban Ionicons (no emoji) — quedaron fuera de este alcance, no hacía falta tocarlos. - Verificado con `ng build` (exit 0) y `grep` de los 4 componentes tocados confirmando cero emojis restantes. --- ### Revisión de pendientes B04/B06/B07 con el usuario - **B04:** sigue pendiente, sin cambios — decisión de no tocar por ahora se mantiene. - **B06 (relay):** el usuario refinó el alcance tras comentarlo con el equipo — se reduce de 3 a **2 estados** (`buscando`/`completo`), se descarta "reemplazo". Se documentó en detalle en el backlog: "buscando" es directo (toggle existente en `perfil-usuario`); "completo" es un dato **derivado** de un flujo de chat (contacto 1:1 → aceptación → chat grupal → conteo de miembros vs `relay_tipo` solicitado). Confirmado con el usuario que la plataforma **ya tiene chat 1:1 y grupal** — solo falta el mecanismo de transición 1:1→grupal, que no debería ser complejo. Sin implementar todavía, solo documentado para cuando se retome. - **B07 (Coach responsable):** el usuario aclaró que **no es un campo nuevo** — es el mismo dato que ya se muestra como "Capitán" en el modal de Club (`club.capitan.nombre`). Se resolvió con un simple ajuste de nomenclatura: - `club-profile-modal.component.html`: label "Capitán" → "Coach responsable". - Botón de contacto: "Contactar al capitán" → "Contactar al coach" (coincide con el mockup real, evita inconsistencia de términos dentro del mismo modal). - Verificado con `ng build` (exit 0). --- ## NEXTs Pendientes abiertos → ver backlog vivo: 📋 [`BCK-EL-Gustavo-RCH-v01.md`](../BCK-EL-Gustavo-RCH-v01.md) Abiertos al cierre de hoy: - **B04** — normalización canónica de valores enum del perfil (roles/rol) y fix del filtro case-sensitive en `getListCoaches()`. - **B06** — relay con 2 estados (buscando/completo), contexto completo documentado (ver backlog), pendiente de implementación: falta el mecanismo de transición de chat 1:1 a grupal y el conteo de miembros vs `relay_tipo`. Completados hoy: - ~~B08~~ — migración de íconos emoji a Material Symbols Rounded. - ~~B07~~ — "Coach responsable" resuelto como renombre de la etiqueta "Capitán" ya existente, no era campo nuevo. Obsoletos hoy (superados por el mockup real v02, ver tabla de obsoletos en el backlog): - ~~B03~~ — badge "Acepta atletas" eliminado de la UI, ya no aplica ratificación. - ~~B05~~ — feature de admisión/cupo eliminada por completo, ya no hay hardcode que migrar. --- ## Estado de git al cierre - **Frontend** (`rebelocity-club`, rama `gustavo`): 4 commits nuevos hechos durante la sesión — `a6e5f66 homologacion`, `a03dc1f homologacion de tarjetas`, `5e321d0 features mockpuo v02`, `dbd467b features mockpuo v02, material symbols integracion`. Queda **1 archivo sin commitear**: `club-profile-modal.component.html` (el rename de B07, "Capitán" → "Coach responsable"). - **Backend** (`archivos-server`): `api_rch/controllers/rebelocity/general.php` modificado y **sin commitear** (todos los cambios de backend de hoy: `getListCoaches()`, `getListAtletas()`, `listClubs()`). Recordar el patrón de despliegue: este repo no tiene remoto, la subida a `genniux.net` es manual — hay que desplegar este archivo para que el B07/mockup v02 tomen efecto en producción.