Saltar al contenido principal

Moderadores de Cuenta — Referencia Técnica

← Volver a Moderadores de Cuenta

Dónde vive esto

Backend

Frontend

Checklist de implementación técnica

  • tabla account_moderator + modelo + asociaciones (owner, moderator) — 9 flags de permisos: canPost, canClip, canLive, canStory, canCreateChats, canSendMessages, canComment, canReact, canManageComments
  • tabla account_moderator_action + modelo — rastro de auditoría de cada acción realizada en nombre de un dueño
  • addModerator / updateModeratorPermissionsrequieren owner.twoFactorEnabled (lanzan moderators.requires_2fa de lo contrario) y una ventana de reautenticación step-up reciente (lanzan moderators.requires_reauth / REQUIRES_REAUTH de lo contrario)
  • verifyPasswordForModerators(password) — reverifica la contraseña del dueño y abre una nueva ventana step-up de 15 minutos
  • removeModerator — no requiere 2FA ni step-up
  • consultas myModerators / accountsIModerate / moderatorActivity
  • aplicación de resolveActingUser(callerId, actAsUserId, action) en createPost (post/clip), createStory, likePost, createLiveStream, createConversation, sendMessage, createComment, deleteComment
  • logAction escribe en el rastro de auditoría cada vez que el usuario efectivo difiere del que llama (best-effort, nunca lanza error)
  • Message.viaModerator — atribución visible solo para el dueño de quién realmente envió un mensaje enviado "como" él
  • "Publicar como" en el compositor de posts, "Comentar como" en el cuadro de comentarios
  • Aplicación de canStorycreateStory acepta actAsUserId y llama a resolveActingUser(..., 'story', ...); esta documentación antes decía que canStory estaba definido de punta a punta pero nunca se aplicaba. Corregido.
  • Aplicación de canReact / canManageCommentslikePost (post-interaction.resolver.js) llama a resolveActingUser(..., 'react', ...) y deleteComment (post-comment.resolver.js) llama a resolveActingUser(..., 'manage_comment', ...); esta documentación antes decía que ningún resolver comprobaba ninguno de los dos permisos. Corregido.
  • Disparador de UI de "actuar como" en los compositores de en vivo / nuevo chat / mensajes — GoLiveModal.tsx (filtrado por canLive), ConversationList.tsx (filtrado por canCreateChats) y ChatView.tsx (filtrado por canSendMessages) ahora exponen un selector de "actuar como" conectado a actAsUserId, el mismo patrón que ya usaban CreatePostModal/PostModal; esta documentación antes decía que en la UI solo estaban conectados posts/clips/comentarios. Corregido.

GraphQL

type ModeratorPermissions {
canPost: Boolean! canClip: Boolean! canLive: Boolean! canCreateChats: Boolean! canSendMessages: Boolean!
canComment: Boolean! canManageComments: Boolean! canStory: Boolean! canReact: Boolean!
}

type AccountModerator {
id: ID!
owner: User
moderator: User
canPost: Boolean! canClip: Boolean! canLive: Boolean! canCreateChats: Boolean! canSendMessages: Boolean!
canComment: Boolean! canManageComments: Boolean! canStory: Boolean! canReact: Boolean!
createdAt: DateTime! updatedAt: DateTime!
}

input ModeratorPermissionsInput {
canPost: Boolean canClip: Boolean canLive: Boolean canCreateChats: Boolean canSendMessages: Boolean
canComment: Boolean canManageComments: Boolean canStory: Boolean canReact: Boolean
}

"A single entry in the account-moderator audit trail (who did what, when)."
type ModeratorAction {
id: ID!
moderator: User
action: String! # post | clip | live | story | create_chat | send_message | comment | manage_comment | react
actedAs: String! # owner | self
targetType: String # post | live_stream | conversation | message | comment
targetId: ID
metadata: JSON
createdAt: DateTime!
}

type Query {
myModerators: [AccountModerator!]!
accountsIModerate: [AccountModerator!]!
moderatorActivity(limit: Int, offset: Int, action: String, moderatorUserId: ID): [ModeratorAction!]!
}

type Mutation {
addModerator(userId: ID!, permissions: ModeratorPermissionsInput!): AccountModerator! # 2FA + step-up required
updateModeratorPermissions(userId: ID!, permissions: ModeratorPermissionsInput!): AccountModerator! # 2FA + step-up required
removeModerator(userId: ID!): Boolean!
verifyPasswordForModerators(password: String!): Boolean! # step-up re-auth
}

# The create/send inputs gain: actAsUserId: ID
# PostCreateInput / StoryCreateInput / LiveStreamCreateInput / ConversationCreateInput / MessageCreateInput / PostCommentCreateInput
# likePost(postId, interactionType, actAsUserId) and deleteComment(commentId, actAsUserId) take actAsUserId
# as a plain argument (not via an input type)

Mapa de permisos → acción

PermisoAcciónResolver
canPostpost regularcreatePost
canClipclip de un solo videocreatePost (clip detectado)
canLiveiniciar un en vivocreateLiveStream
canCreateChatscrear una conversacióncreateConversation
canSendMessagesenviar un mensajesendMessage
canCommentcomentar / responder en un postcreateComment (post-comment.resolver.js)
canStorypublicar una historiacreateStory
canReactreaccionar/dar likelikePost (post-interaction.resolver.js)
canManageCommentsmoderar/eliminar un comentariodeleteComment (post-comment.resolver.js)

Configuración

Ejecuta 20260721130000-create-account-moderator y 20260721150000-expand-account-moderator, luego reinicia el backend. No hay variables de entorno nuevas. El dueño debe habilitar 2FA (Configuración → Seguridad) antes de otorgar acceso de moderador; añadir/actualizar moderadores también requiere una ventana step-up reciente (services/step-up-auth.service.js, respaldada por Redis, 15 minutos), que el dueño puede (re)abrir mediante verifyPasswordForModerators.