Moderación de usuarios
Los administradores y moderadores pueden buscar usuarios, ver su historial de moderación, y tomar acciones — advertencias, suspensiones, baneos y verificación — desde el panel de administración.
Checklist de implementación
Buscar y ver usuarios
- Buscar y listar usuarios con filtros (
adminGetUsers- backend listo, conectado a la página de listado de usuarios) - Obtener el perfil de moderación de un usuario (
adminGetUserDetails- backend listo, conectado a la página de detalle de usuario) - Obtener el historial de acciones de moderación de un usuario (
adminGetUserModerationHistory- conectado a la sección "Historial de moderación" de la página de detalle de usuario) - Estadísticas de usuarios a nivel de plataforma (
adminGetUserStats- conectado a las tarjetas de estadísticas de la página de listado de usuarios) - Las queries
adminGetSuspendedUsers,adminGetBannedUsers,adminGetUserSuspensionsyadminGetUserWarningshan sido eliminadas del esquema (ya no están enadmin/user-moderation.type.jsni enadmin/user-moderation.resolver.js). La página de listado de usuarios sigue filtrando por estado medianteadminGetUsersen su lugar; los conteos de suspensiones/advertencias por usuario se muestran a través deadminGetUserDetails(warningCount) y el historial a través deadminGetUserModerationHistory. El manager todavía tiene los métodosgetSuspendedUsers/getBannedUsers/getUserSuspensions/getUserWarningsenuser-moderation.manager.js, pero ahora son código muerto inalcanzable - ningún resolver los llama.
Suspender, advertir y banear
- Suspender a un usuario (
adminSuspendUser- backend listo, conectado a la página de detalle de usuario) - Levantar una suspensión (
adminUnsuspendUser- backend listo, conectado a la página de detalle de usuario) - Emitir una advertencia (
adminWarnUser- conectado a la página de detalle de usuario. Corregido en esta sesión: pasaba el ID del administrador emisor comoissued_by, perocreate()deuser-warnings.access-service.jssolo leeadminId/admin_id- la columnaadmin_idde la advertencia persistida siempre quedaba enNULL.) - Banear a un usuario (
adminBanUser- conectado a la página de detalle de usuario. Corregido en esta sesión: cuando se solicita "también eliminar contenido" llama internamente aremoveUserContent, pero lo hacía con solo 3 de sus 5 argumentos, así quecontextcaía en la posición dereasonyadminId/contextquedaban ambosundefinedmás abajo - inofensivo por coincidencia ya queremoveUserContenttampoco usaba esos parámetros, pero un desajuste de firma real; ahora pasa los 5 en orden.) - Revertir un baneo (
adminUnbanUser- backend listo, conectado a la página de detalle de usuario) - Eliminar el contenido de un usuario (posts/comentarios) (
adminRemoveUserContent- conectado a la acción "Eliminar contenido" de la página de detalle de usuario, con un selector de tipo de contenido: ALL/POSTS/COMMENTS. Corregido en esta sesión: la rama POSTS llamaba apostAccessService.findByUser(), un método que no existe (el método real esgetByUser) - el error resultante era silenciosamente absorbido por el try/catch que lo rodeaba, lo cual significaba quecontentType: 'ALL'omitía silenciosamente POSTS y todo tipo de contenido posterior dentro del mismo bloque try, mientras seguía reportandosuccess: true. El selector antes también ofrecía BLASTS/TALES/ARTICLES; se eliminaron porque nunca tuvieron un modelo de backend real — ver la nota del enumContentTypeen la referencia técnica de Moderación de Contenido.)
Moderación masiva
- Suspender usuarios en lote (solo super_admin) (
adminBulkSuspendUsers- conectado a la acción de selección en lote + "Suspender seleccionados" de la página de listado de usuarios) - Banear usuarios en lote (solo super_admin) (
adminBulkBanUsers(userIds, reason, permanent)- el resolver está protegido porisSuperAdmin→userModerationManager.bulkBanUsers, que llama abanUserpor cada usuario condeleteContent: false, notifyUser: false. Corregido en esta sesión: su tipo de retorno eraModerationActionResponse(success/message/actionId), que no expone lossuccessCount/failedCount/total/errorsque el manager ya calcula por usuario - se amplió a un nuevo tipoUserBulkOperationResponse(adminBulkSuspendUsersse amplió de la misma forma, mismo hueco latente). Conectado a un botón "Banear seleccionados" en la barra de selección múltiple de la página/users, solo super_admin, junto a la acción de suspensión en lote ya existente; un resultado parcialmente fallido ahora muestra un mensaje en línea "N exitosos, M fallidos" en lugar de un éxito ciego.)
Verificación (esquema de administrador)
- Otorgar una insignia de verificación (
adminVerifyUser- backend listo, conectado a la página de detalle de usuario) - Revocar una insignia de verificación (
adminRemoveVerification- conectado a la acción "Quitar verificación" de la página de detalle de usuario, se muestra una vez que un usuario está verificado)
Estas son independientes del flujo de solicitud de verificación orientado al cliente (getPendingVerificationRequests / grantVerification / removeVerification / rejectVerificationRequest), que vive en el esquema de cliente y está documentado en Verificación. Ambas son implementaciones reales e independientes de una funcionalidad similar, en esquemas distintos con modelos de autenticación distintos.
Referencia técnica
Ver Panel de administración → Gestión de usuarios para la API completa de GraphQL.