Clips — Referencia técnica
Dónde vive esto
Backend
apps/backend/graphql/types/post.type.js—clips(limit: Int, offset: Int): [Post!]!, documentado en línea como "Posts of type='clip' (uploaded as a single video, no images) - backs the full-screen vertical Clips feed"apps/backend/graphql/resolvers/post.resolver.js— el resolverclipsllama apostManager.getClips; para quienes llaman de forma anónima (!context.user) pasapublicOnly: trueapps/backend/managers/post-managers/post.manager.js—getClips— delega enpostAccessService.getByType('clip', options)apps/backend/data-access-services/post/post.access-service.js—getByType(type, options)— cuandopublicOnlyestá activo (navegación sin sesión iniciada) restringe además avisibility: 'public',isPublished: true, y excluye los posts de cuentas privadas (creator.isPrivate: false)
Un clip no es un modelo distinto — es un Post con type: 'clip', asignado al momento de crearlo cuando el post tiene exactamente un video adjunto y ninguna imagen. No existe un tipo de GraphQL "Clip" separado; clips devuelve objetos Post normales.
Frontend
apps/frontend-nextjs/src/page-components/ClipsPage.tsx— el feed vertical a pantalla completa para usuarios autenticados; consultaclips, y reutiliza las mismas mutations de "me gusta"/guardar/republicar que usaPostCard.tsx(hasUserLikedPost/likePost,isPostSaved/savePost,hasUserReposted/repostPost/undoRepost)apps/frontend-nextjs/src/page-components/PublicClipsPage.tsx— vista sin sesión iniciada: una cuadrícula de desplazamiento infinito con clips públicos (consultaclips, apoyándose en el filtradopublicOnlydel resolver); tocar una miniatura abrePublicPostViewer, y las interacciones redirigen a/loginapps/frontend-nextjs/src/components/public/BrowseGate.tsx— elige entreClipsPageyPublicClipsPagesegúnuseAuth().isAuthenticatedapps/frontend-nextjs/src/app/clips/page.tsx— ruta/clips; renderizaBrowseGateconClipsPage/PublicClipsPageapps/frontend-nextjs/src/components/Navigation.tsx— enlace a Clips en la barra lateral de escritorio (ClipIcon), ubicado justo después de Explorar; también es el elemento central de la barra inferior en móvilapps/frontend-nextjs/src/components/PostModal.tsx— se abre desdeClipsPage.tsxpara manejar los comentarios de un clip, el mismo modal que usa el feed normalapps/frontend-nextjs/src/components/stories/CreateClipModal.tsx— un compositor funcional centrado en video ya construido (selector de archivos o captura vía getUserMedia/MediaRecorder, leyenda, selector de audiencia, llama acreatePost). Corregido en esta sesión: antes solo lo importaba una historia de Storybook (StoriesFeature.stories.tsx), inaccesible desde cualquier página real (un botón flotante "+" anterior enClipsPage.tsxque lo abría había sido eliminado, commit835c2de6, "drop redundant Clips upload FAB", en favor de crear clips a través del compositor de posts normal).ClipsPage.tsxahora lo importa directamente y lo renderiza detrás de un flag de estadoshowCreateClip, abierto mediante un botón flotante "Crear clip" (arriba a la derecha, íconoPlus, visible solo cuandoauthUserestá definido)
Checklist de implementación técnica
- Query
clips— conectado de punta a punta;ClipsPage.tsx(con sesión iniciada) yPublicClipsPage.tsx(sin sesión iniciada, solo contenido público) - Dar / quitar "me gusta" — conectado; comparte las mutations
hasUserLikedPost/likePostdePostCard.tsx - Guardar / quitar de guardados — conectado; comparte las mutations
isPostSaved/savePost - Republicar / deshacer republicación — conectado; comparte las mutations
hasUserReposted/repostPost/undoRepost - Comentar — conectado vía el
PostModal.tsxcompartido - Interfaz dedicada para crear Clips (flujo de grabación/subida con cámara) — Corregido en esta sesión:
CreateClipModal.tsxestá completamente construido y ahora montado enClipsPage.tsxdetrás de un botón flotante "Crear clip"; los clips también se pueden seguir produciendo con el compositor de posts normal (CreatePostModal.tsx) cuando se adjunta un solo video
Query del feed
query GetClips($limit: Int, $offset: Int) {
clips(limit: $limit, offset: $offset) {
id
text
userId
createdAt
user { id username profilePicture }
media { id mediaUrl mediaType width height }
}
}
ClipsPage.tsx sigue el mismo patrón de alternancia optimista que PostCard.tsx para "me gusta"/guardar/republicar — consulta el estado actual (hasUserLikedPost, isPostSaved, hasUserReposted) por cada clip visible y actualiza el estado local de inmediato al tocar, antes de que la mutation se resuelva.