API de administración de experiencias (/experiencias)¶
Para quién es: el equipo de desarrollo. Con esta API se crean, configuran, activan, desactivan y retiran las experiencias visuales del
Sistema de Experiencias desde un panel de la aplicación, sin tocar la base de datos ni variables de entorno.
Es una herramienta solo para desarrollo; los usuarios finales solo usan /preferencias/mia.
No usar /metodoGenerico para estas colecciones
Las colecciones Experiencias y PreferenciasUsuario se escriben únicamente con la Lambda ApiLambdaPreferenciasUsuario (las rutas de esta
página y de /preferencias/mia). Nunca las modifiquen con /metodoGenerico ni con insertarGenerico, MongoDB Compass o scripts propios (la única excepción son los scripts de preparación del repo, que solo crean índices y la semilla de clasica):
se saltan las reglas de negocio (la experiencia clasica intocable, el control de versión, el formato de los ids, la auditoría en logs).
La Lambda genérica hoy no tiene lista blanca de colecciones, así que el sistema no lo impide: lo impide el equipo. Un documento
inválido se ignora al leer el catálogo (nunca llega a los usuarios), pero un cambio mal hecho puede dejar una experiencia sin aparecer.
| Entorno | URL base | Estado |
|---|---|---|
| PreProd | https://8u5isw5u30.execute-api.us-east-1.amazonaws.com/PreProd |
Disponible cuando el backend se despliega y valida en PreProd |
| Producción | https://7elgyten88.execute-api.us-east-1.amazonaws.com/Produccion |
Todavía no. Al montarla, ROLES_ADMIN_EXPERIENCIAS puede quedar vacío (nadie administra) |
Autenticación y errores: igual que /preferencias/mia: header Token: <id_token de Cognito>, errores { "codigo", "traceId" }.
Quién puede qué¶
| Acción | Quién |
|---|---|
Leer (GET) |
Cualquier usuario autenticado, pero cada uno solo ve las experiencias que sus roles le permiten (misma regla que disponibles). Lo que no puede ver responde 404, igual que lo que no existe |
| Crear, editar, cambiar estado, borrar | Solo roles de la variable de entorno ROLES_ADMIN_EXPERIENCIAS (en PreProd: Desarrollador,CEO). Los roles se leen de Users por el sub del token; nunca del cuerpo. Variable vacía = nadie administra |
Ver todo el catálogo (?todas=true) y los campos de administración |
Solo administradores |
La colección Experiencias¶
{
"id": "prueba-interna", // único, no cambia: ^[a-z][a-z0-9-]{1,39}$
"nombre": "Prueba interna", // 2-60 caracteres, sin < >
"descripcion": "Para probar", // 0-200 caracteres
"estado": "borrador", // borrador | beta | general | retirada
"rolesAcceso": ["Piloto"], // roles EXTRA que la ven mientras esté en borrador o beta (máx. 20)
"temas": ["claro"], // 1-10 ids de tema
"temaPorDefecto": "claro", // debe estar en temas
"orden": 100, // 0-9999, menor primero en el selector
"version": 3, // control de concurrencia
"creadoEn": "2026-11-10T12:00:00Z", "creadoPor": "<sub>",
"actualizadoEn": "2026-11-10T12:00:00Z", "actualizadoPor": "<sub>"
}
Quién ve cada estado: general → todos · beta → rol Experiencia, Desarrollador y los de rolesAcceso · borrador → Desarrollador y los de
rolesAcceso · retirada → nadie. No hay límite de experiencias ni reglas de transición: cualquier estado puede pasar a cualquier otro
(activar, desactivar, volver a borrador, retirar, reactivar). La única excepción es clasica.
La experiencia clasica es intocable: siempre existe, siempre es general y no se puede borrar ni cambiar de estado (403 EXPERIENCIA_PROTEGIDA).
Sí se pueden editar su nombre, descripción, orden y temas. Aunque la colección esté vacía o alguien manipule su documento, la plataforma sigue
sirviendo clasica como general.
Qué pasa con los usuarios cuando se cambia una experiencia: nada se modifica en sus datos. Quien tenía guardada una experiencia que ya no puede ver
recibe clasica en su siguiente GET /preferencias/mia. Si el tema que tenía ya no existe en su experiencia, recibe el temaPorDefecto.
Los cambios no son instantáneos: la Lambda cachea el catálogo en memoria 60 segundos por instancia. El cambio se ve de inmediato en la instancia que
lo hizo y en máximo ~60 s en las demás (CACHE_CATALOGO_SEG). Las lecturas de administración (GET de un administrador) van siempre a la colección.
Endpoints¶
| Método y ruta | Quién | Éxito |
|---|---|---|
GET /experiencias |
cualquier autenticado | 200 { "experiencias": [...] } |
GET /experiencias/{id} |
cualquier autenticado | 200 |
POST /experiencias |
admin | 201 + el documento |
PUT /experiencias/{id} |
admin | 200 + el documento |
PUT /experiencias/{id}/estado |
admin | 200 + el documento |
DELETE /experiencias/{id}?version=N |
admin | 204 sin cuerpo |
El OPTIONS de cada ruta lo responde la Lambda (preflight CORS, sin token).
Vista pública (usuario común): id, nombre, descripcion, estado, temas, temaPorDefecto, orden.
Vista de administración (admin): además rolesAcceso, version, creadoEn, creadoPor, actualizadoEn, actualizadoPor.
GET /experiencias¶
Lo visible para el usuario, ordenado por orden. ?todas=true (solo admin) devuelve todo el catálogo, incluidas las retirada. Un usuario no admin con todas=true recibe 403 SIN_PERMISO. Cualquier valor de todas distinto de true o false es 400.
POST /experiencias¶
{ "id": "prueba-interna", "nombre": "Prueba interna", "descripcion": "Para probar", "estado": "borrador",
"rolesAcceso": [], "temas": ["claro"], "temaPorDefecto": "claro", "orden": 100 }
id y nombre son obligatorios. Por defecto: estado borrador, rolesAcceso [], temas ["claro"], temaPorDefecto "claro", orden 100. Nace con version 1.
PUT /experiencias/{id} (editar)¶
{ "nombre": "Prueba interna 2", "descripcion": "", "rolesAcceso": ["Piloto"], "temas": ["claro", "oscuro"], "temaPorDefecto": "claro", "orden": 120, "version": 3 }
descripcion, opcional). No cambia el id ni el estado. Suma 1 a la version.
PUT /experiencias/{id}/estado¶
Cualquier estado a cualquier otro. Para clasica siempre 403 EXPERIENCIA_PROTEGIDA.
DELETE /experiencias/{id}?version=N¶
La version va en la query (1 a 1 000 000). Regla de borrado: solo se borra si la experiencia está en borrador o retirada y ningún usuario la tiene
guardada. En cualquier otro caso no se borra: se retira (PUT …/estado con retirada). El orden en que se comprueba y lo que responde:
| # | Condición | HTTP | codigo |
Qué hacer |
|---|---|---|---|---|
| 1 | No es administrador | 403 | SIN_PERMISO |
— |
| 2 | Es clasica |
403 | EXPERIENCIA_PROTEGIDA |
No se puede borrar nunca |
| 3 | No existe | 404 | EXPERIENCIA_NO_ENCONTRADA |
— |
| 4 | La version no es la actual |
409 | CONFLICTO_VERSION |
Volver a leerla (GET) y reintentar |
| 5 | Está en beta o general |
409 | ESTADO_NO_PERMITE_BORRAR |
Pasarla antes a borrador o retirada |
| 6 | Algún usuario la tiene guardada | 409 | EXPERIENCIA_EN_USO |
No se borra: se deja retirada (los usuarios reciben clasica) |
| — | Todo en orden | 204 | — | Borrada, sin cuerpo |
Un version ausente o mal formado es 400 VALIDACION. Si alguien guarda justo esa experiencia entre la comprobación y el borrado (o desde una instancia con la caché vieja), el borrado puede
alcanzar a ese usuario: él recibirá clasica (mismo efecto que retirar) y queda un [WARN] eliminada-con-usuarios en los logs. Si se vuelve a crear el mismo id con otro contenido, ese usuario lo heredaría sin haberlo elegido: evite reutilizar ids borrados.
Detalles que conviene saber¶
- El administrador ve más:
GET /experiencias/{id}yGET /experiencias?todas=truedevuelven a un administrador cualquier experiencia (incluidasborradoryretirada) para poder editarla; un usuario común solo ve lo que su rol permite. - Un documento inválido en la colección (alterado a mano, por ejemplo con un estado que no existe) se ignora al leer el catálogo: la API lo trata como inexistente (
GET/PUT/DELETEdan404) y unPOSTcon ese mismoidda409 EXPERIENCIA_YA_EXISTE. Un[WARN] experiencia-invalida id=… motivo=…queda en los logs. Se repara corrigiendo el documento (por un script de Iker, nunca con/metodoGenerico). - Caracteres no permitidos: el nombre, la descripción y los roles rechazan
<>y los caracteres de control, de formato (invisibles, de dirección, como U+200B o U+202E), separadores de línea y párrafo, y UTF-16 inválido (400 VALIDACION). - El permiso se comprueba antes que el cuerpo: un usuario sin rol de administración recibe
403 SIN_PERMISOaunque su cuerpo sea inválido.
Todos los códigos¶
| HTTP | codigo |
Cuándo |
|---|---|---|
| 400 | VALIDACION |
JSON inválido, campo extra/repetido/faltante, tipo o formato incorrecto, id de la ruta mal formado, version mal formada |
| 401 | SIN_TOKEN · TOKEN_INVALIDO · USUARIO_NO_ENCONTRADO |
Sin sesión válida |
| 403 | SIN_PERMISO |
El usuario no tiene un rol de ROLES_ADMIN_EXPERIENCIAS (o pidió todas=true) |
| 403 | EXPERIENCIA_PROTEGIDA |
Borrar o cambiar de estado clasica |
| 404 | EXPERIENCIA_NO_ENCONTRADA |
No existe o no es visible para el usuario |
| 405 | METODO_NO_PERMITIDO |
Método que la ruta no admite (la cabecera Allow lista los permitidos) |
| 409 | EXPERIENCIA_YA_EXISTE |
POST con un id que ya existe (incluido clasica) |
| 409 | CONFLICTO_VERSION |
La version enviada no es la guardada |
| 409 | ESTADO_NO_PERMITE_BORRAR · EXPERIENCIA_EN_USO |
Ver la tabla del DELETE |
| 413 | CUERPO_DEMASIADO_GRANDE |
Más de 8192 bytes |
| 500 | ERROR_INTERNO |
Fallo no controlado, configuración inválida o falta un índice único (sin detalles) |
Auditoría¶
La auditoría va a los logs de la Lambda (CloudWatch /aws/lambda/ApiLambdaPreferenciasUsuario), una línea por escritura, sin nombres ni datos personales:
[AUDIT] trace=3fa85f6457a1 sub=<sub> accion=ESTADO id=prueba-interna estado=beta->general
[AUDIT] trace=… sub=<sub> accion=CREAR|EDITAR|ESTADO|ELIMINAR id=…
creadoPor/En y actualizadoPor/En. No existe (por ahora) una colección de historial; si los controles de auditoría lo piden, se crea.
Cómo consumirla (panel de desarrollo)¶
- Al abrir el panel:
GET /experiencias?todas=true(solo se muestra a quien tenga rol de administración; para los demás, el front oculta el panel). - Guarde la
versionde cada documento y envíela en cadaPUTyDELETE. Ante409 CONFLICTO_VERSION: vuelva a leer y muestre el cambio. - Muestre
nombre,descripcionyestadocontextContent(nuncainnerHTML): aunque la API rechaza<y>, el front no debe confiar en ello. - Cree la experiencia en
borrador, pruébela con un usuarioDesarrollador(o conrolesAcceso), pásela abeta, y por último ageneral. - Al crear una experiencia recuerde que el código de la experiencia vive en el front (
experiencias/<id>/): si elidno está en el registro del front, el front la ignora y usaclasica. - Los cambios pueden tardar hasta ~60 s en verse para todos los usuarios.
Documentos relacionados¶
API de Preferencias · OpenAPI · Ficha de la Lambda y operación · ADR-002