Files
feadulta/docs/handoff-tecnico-rafa-issues-174-175-2026-07-15.md
T
rafa 69e849d38e Sync: guardar en el historial el trabajo de las ultimas semanas que solo vivia en el disco
Este repo local tenia origin apuntando al Gitea local (localhost:3000), que Rafa
declaro archivado el 2026-06-28 (commit 962f33a, desarrollo movido a
gitea.feadulta.com). Ese memo nunca llego a este checkout: main quedo congelado
y todo el trabajo real de las ultimas 3+ semanas se fue commiteando solo en la
rama fix/multiidioma-portada-132 (ya fusionada a main sin perdida, commit
2504666), mientras que ademas se acumulaban 78 cambios sin commitear en el
working tree que nunca llegaron a NINGUN historial de git.

Este commit consolida esos cambios sueltos: TTS multi-voz (tts_*.py), scripts
de traduccion (translate_haiku.py, pretranslate_en_haiku.py, sync_translations_to_prod.py),
mu-plugins nuevos desplegados a prod (fea-beta-feedback, fea-cloudflare-realip,
fea-legacy-redirect, fea-gsc-verification, fea-support-campaign, fea-ui, etc.),
scripts de mantenimiento de enlaces/cartas, capturas E2E (tools/e2e/shot_*.cjs)
y documentacion de sesiones recientes.

Excluido deliberadamente (no es codigo versionable): tts-voices/ (3.3GB de
muestras de audio para clonacion de voz, anadido a .gitignore), logs/ (logs de
ejecucion, anadido a .gitignore), y 2 ficheros vacios accidentales + 2 copias
duplicadas sueltas en la raiz que ya existen en su ubicacion correcta.
2026-07-15 20:03:21 -04:00

181 lines
6.2 KiB
Markdown

# Handoff técnico para Rafa — issues #174 y #175
## Alcance
Preparación técnica solamente. **No aplicar en producción desde aquí.**
---
## Issue #174 — cierre autónomo de la carta (publicar + rotar)
### Regla funcional confirmada por Inma/Mixbot
La rotación que ya funcionó hoy manualmente por WP REST API para la carta 735 es esta, y **solo para el post ES**:
1. **nueva carta** → añadir cat **6** (`carta actual`)
2. **la que estaba en cat 6** → quitar cat 6, añadir cat **22** (`semana pasada`), manteniendo cat **21** (`archivo acumulativo`)
3. **la que estaba en cat 22** → quitar cat 22, dejar solo cat **21**
4. **no tocar traducciones** en este paso
### Decisión pendiente para Rafa
Hay dos caminos válidos:
#### Opción A — adaptar `rotate_cartas.php` a ES-only
Pros:
- reutiliza lógica ya existente y conocida en el repo
- más coherente con el toolkit actual de scripts
- fácil dejar `DRY-RUN` + `APPLY=1`
Contras:
- hay que modificar el script actual porque hoy rota todos los idiomas
- si Mixbot publica por REST y la rotación la hace otro script aparte, el flujo queda repartido en dos piezas
#### Opción B — que Mixbot haga la rotación por WP REST API
Pros:
- ya está validado en vivo hoy
- mantiene toda la operación editorial en el mismo sitio donde ya se publica la carta
- evita acoplar la decisión editorial a un script server-side adicional
Contras:
- la lógica queda fuera del repo de scripts PHP si no se documenta bien
- conviene dejarla muy explícita para no divergirse del comportamiento esperado
### Recomendación técnica
Mi lectura: **cualquiera vale**, pero elegiría según quién vaya a mantenerlo:
- si Rafa quiere la lógica **versionada y centralizada en el repo**, mejor **A: `rotate_cartas.php` ES-only**
- si Inma/Mixbot ya tienen el flujo sólido y prefieren autonomía total desde su lado, mejor **B: REST API desde Mixbot**, con la lógica documentada en el issue/runbook
### Si Rafa elige A (script ES-only), propuesta concreta
Crear una variante mínima o adaptar `rotate_cartas.php` con estas reglas:
- entrada: `CARTA=<es_id>`
- lookup solo en idioma `es`
- localizar:
- `actual_es` = post con cat 6
- `pasada_es` = post con cat 22
- `nueva_es` = `CARTA`
- operaciones:
- `pasada_es` pierde 22, conserva 21
- `actual_es` pierde 6, gana 22, conserva 21
- `nueva_es` gana 6 y conserva/gana 21
- **nunca tocar** posts EN/FR/IT/PT
- mantener modo `DRY-RUN`
### Dry-run deseable para Rafa
Salida ideal del dry-run:
- `nueva_es=#54495 -> +6 (+21 si faltaba)`
- `actual_es=#54254 -> -6 +22 (mantiene 21)`
- `pasada_es=#53984 -> -22 (mantiene 21)`
- `translations untouched`
### Decisión funcional que conviene dejar escrita
Para evitar ambigüedad futura, dejar explícito en el issue o en el script:
- `21` es acumulativa y la conservan todas las cartas archivables
- `6` y `22` son mutuamente excluyentes
- la rotación editorial inicial afecta **solo al ES**
- las traducciones rotan/publican en un paso posterior independiente
---
## Issue #175 — endpoint `subir-avatar`
### Base ya existente
El sistema actual ya tiene casi todo:
- frontend lee `user_meta('foto_perfil')`
- `face_crop_avatar.py` ya resuelve recorte/centrado de cara
- `regen_avatars.php` ya existe para regeneración/ajustes
- caso real listo para probar: **Silvia Martínez Cano**, `user_id=1112`, `slug=silvia-mtnz`
### Contrato recomendado
Yo le propondría a Rafa este contrato por simplicidad operativa:
#### Endpoint
`POST /wp-json/fea/v1/subir-avatar`
#### Auth
La misma Application Password que ya usa `crear-autor` (`#166`), con el mismo criterio de permisos.
#### Identificador
**`user_id`** mejor que `slug`.
Motivo:
- Mixbot ya lo tiene en el roster
- evita ambigüedades por slug cambiado / transliteraciones / colisiones
- simplifica el lookup
#### Formato de entrada
**multipart/form-data** mejor que base64.
Motivo:
- más natural para subir imágenes
- menos overhead
- encaja mejor con `media_handle_sideload` / manejo típico WP
- más fácil de depurar que base64
#### Campo esperado
- `user_id` (obligatorio)
- `file` (obligatorio)
Opcionalmente:
- `crop=server|client` si Rafa quiere dejar ambas puertas abiertas, aunque probablemente es overkill de entrada
### Recomendación de procesamiento
Mi recomendación clara: **que el endpoint NO haga face-crop complejo** en la primera versión.
Mejor v1:
- Mixbot/Inma mandan la imagen **ya cuadrada**
- estándar objetivo: **1254x1254** (el que ya usáis)
- el endpoint solo:
1. valida usuario
2. guarda attachment
3. actualiza `foto_perfil`
4. devuelve `attachment_id`, `user_id`, `url`
Pros:
- mucho menos riesgo y menos dependencias server-side
- evita meter OpenCV/Pillow/lógica pesada dentro del endpoint
- más fácil de testear e idempotente
- si mañana queréis face-crop automático, se añade en v2
### Comportamiento recomendado del endpoint
- requiere login + permiso tipo `edit_others_posts` (igual filosofía que `crear-autor`)
- valida que `user_id` exista
- acepta solo imagen (`jpg`, `jpeg`, `png`, `webp` si WP lo admite ahí)
- crea attachment en Media Library
- hace `update_user_meta($user_id, 'foto_perfil', $attachment_id)`
- respuesta JSON:
- `user_id`
- `display_name`
- `attachment_id`
- `url`
- `updated: true`
### Idempotencia mínima útil
No hace falta obsesionarse en v1, pero sí conviene:
- si se vuelve a subir otra foto para el mismo `user_id`, simplemente reemplazar el `foto_perfil` al nuevo attachment
- opcional: si el hash del fichero coincide con el ya asignado, devolver `updated:false`
### Caso piloto sugerido
Primera prueba con:
- `user_id=1112`
- `slug=silvia-mtnz`
- imagen ya recortada por Inma/Mixbot a **1254x1254**
Así la prueba valida solo el endpoint, no el pipeline de crop.
---
## Cierres administrativos
Por estado funcional, salvo sorpresa:
- `#166` → cerrable
- `#168` → cerrable
- `#170` → cerrable
---
## Recomendación final para Rafa
Si quiere minimizar trabajo y riesgo:
- **#174**: usar la lógica que ya validó Mixbot hoy, y solo portar al repo si él prefiere centralizar
- **#175**: endpoint mínimo con `user_id` + multipart + imagen ya cuadrada a 1254x1254
Eso deja la autonomía mucho más cerca sin meterse en una refactor rara.