From 4b355f63ac746b5b7e8feb6cee23e9dfe07e3dc2 Mon Sep 17 00:00:00 2001 From: michaelschal <35957947-michaelschal@users.noreply.replit.com> Date: Fri, 31 Oct 2025 15:02:00 +0000 Subject: [PATCH 1/5] Transitioned from Plan to Build mode Replit-Commit-Author: Agent Replit-Commit-Session-Id: ae4037a0-2a6f-4530-9bac-79b543286bda Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 87b3594a-183a-4abd-8320-a109db275ea6 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/397bca8c-984f-43ff-841a-10897aeb8140/ae4037a0-2a6f-4530-9bac-79b543286bda/cOs6ffF From 7f031904dd622c7cf873714b56fd4cadca1a052c Mon Sep 17 00:00:00 2001 From: michaelschal <35957947-michaelschal@users.noreply.replit.com> Date: Fri, 31 Oct 2025 15:03:40 +0000 Subject: [PATCH 2/5] Improve video upload functionality and add diagnostics for Android Expand accepted video file types and implement debugging logs for camera captures on Android to address upload issues. Replit-Commit-Author: Agent Replit-Commit-Session-Id: ae4037a0-2a6f-4530-9bac-79b543286bda Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Event-Id: 768a5377-a884-497c-93f6-6ce6c925d1d2 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/397bca8c-984f-43ff-841a-10897aeb8140/ae4037a0-2a6f-4530-9bac-79b543286bda/cOs6ffF --- client/src/components/media-upload.tsx | 26 ++++++++++++++++++++++++-- client/src/pages/new-post.tsx | 25 +++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/client/src/components/media-upload.tsx b/client/src/components/media-upload.tsx index 6200180..e8fa4b3 100644 --- a/client/src/components/media-upload.tsx +++ b/client/src/components/media-upload.tsx @@ -95,8 +95,8 @@ export default function MediaUpload() { const { getRootProps, getInputProps, isDragActive, open } = useDropzone({ onDrop, accept: { - "image/*": [".png", ".jpg", ".jpeg", ".gif"], - "video/*": [".mp4", ".mov"], + "image/*": [".png", ".jpg", ".jpeg", ".gif", ".webp"], + "video/*": [".mp4", ".mov", ".webm", ".3gp", ".3gpp", ".mkv", ".avi"], }, maxSize: 52428800, multiple: true, @@ -115,13 +115,35 @@ export default function MediaUpload() { const handleCameraCapture = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (file) { + // Logs de diagnostic pour Android + console.log('đŸ“č Capture camera dĂ©tectĂ©e:', { + nom: file.name, + type: file.type, + taille: `${(file.size / 1024 / 1024).toFixed(2)} MB`, + estVideo: file.type.startsWith('video/') + }); + // Correction Android : crĂ©er un nom valide si le fichier n'a pas de nom let fileToUpload = file; if (!file.name || file.name === 'blob' || file.name === '') { const extension = file.type.split('/')[1] || 'jpg'; const newFileName = `camera-${Date.now()}.${extension}`; fileToUpload = new File([file], newFileName, { type: file.type }); + console.log('✅ Nom de fichier corrigĂ©:', newFileName); } + + // VĂ©rification taille (50 MB max) + if (file.size > 52428800) { + toast({ + title: "Fichier trop volumineux", + description: `La taille maximale est de 50 MB. Votre fichier fait ${(file.size / 1024 / 1024).toFixed(2)} MB`, + variant: "destructive", + }); + console.error('❌ Fichier rejetĂ©: trop volumineux'); + e.target.value = ''; + return; + } + uploadMutation.mutate(fileToUpload); // RĂ©initialiser l'input pour permettre de capturer la mĂȘme photo Ă  nouveau e.target.value = ''; diff --git a/client/src/pages/new-post.tsx b/client/src/pages/new-post.tsx index d817c7c..070ee8d 100644 --- a/client/src/pages/new-post.tsx +++ b/client/src/pages/new-post.tsx @@ -180,8 +180,8 @@ export default function NewPost() { const { getRootProps, getInputProps, isDragActive, open } = useDropzone({ onDrop, accept: { - "image/*": [".png", ".jpg", ".jpeg", ".gif"], - "video/*": [".mp4", ".mov"], + "image/*": [".png", ".jpg", ".jpeg", ".gif", ".webp"], + "video/*": [".mp4", ".mov", ".webm", ".3gp", ".3gpp", ".mkv", ".avi"], }, maxSize: 52428800, noClick: true, @@ -299,13 +299,34 @@ export default function NewPost() { const handleCameraCapture = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (file) { + // Logs de diagnostic pour Android + console.log('đŸ“č Capture camera dĂ©tectĂ©e:', { + nom: file.name, + type: file.type, + taille: `${(file.size / 1024 / 1024).toFixed(2)} MB`, + estVideo: file.type.startsWith('video/') + }); + // Correction Android : crĂ©er un nom valide si le fichier n'a pas de nom let fileToUpload = file; if (!file.name || file.name === 'blob' || file.name === '') { const extension = file.type.split('/')[1] || 'jpg'; const newFileName = `camera-${Date.now()}.${extension}`; fileToUpload = new File([file], newFileName, { type: file.type }); + console.log('✅ Nom de fichier corrigĂ©:', newFileName); } + + // VĂ©rification taille (50 MB max) + if (file.size > 52428800) { + toast({ + title: "Fichier trop volumineux", + description: `La taille maximale est de 50 MB. Votre fichier fait ${(file.size / 1024 / 1024).toFixed(2)} MB`, + variant: "destructive", + }); + console.error('❌ Fichier rejetĂ©: trop volumineux'); + return; + } + uploadMutation.mutate(fileToUpload); } }; From 61a381759695f791e66277ec4cc752d7926c2e9a Mon Sep 17 00:00:00 2001 From: michaelschal <35957947-michaelschal@users.noreply.replit.com> Date: Fri, 31 Oct 2025 15:05:12 +0000 Subject: [PATCH 3/5] Enable users to upload videos to the platform on all devices Reset the file input value after a file upload or rejection to prevent issues with subsequent uploads on Android. Replit-Commit-Author: Agent Replit-Commit-Session-Id: ae4037a0-2a6f-4530-9bac-79b543286bda Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Event-Id: 514638b9-84d2-4a7a-8ec1-ae6513635dd7 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/397bca8c-984f-43ff-841a-10897aeb8140/ae4037a0-2a6f-4530-9bac-79b543286bda/ofL5rPP --- client/src/pages/new-post.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/src/pages/new-post.tsx b/client/src/pages/new-post.tsx index 070ee8d..73dd561 100644 --- a/client/src/pages/new-post.tsx +++ b/client/src/pages/new-post.tsx @@ -324,10 +324,12 @@ export default function NewPost() { variant: "destructive", }); console.error('❌ Fichier rejetĂ©: trop volumineux'); + e.target.value = ''; return; } uploadMutation.mutate(fileToUpload); + e.target.value = ''; } }; From 077501e0b9038e3e996a40ca4375fe0c86bf0d7a Mon Sep 17 00:00:00 2001 From: michaelschal <35957947-michaelschal@users.noreply.replit.com> Date: Fri, 31 Oct 2025 15:06:08 +0000 Subject: [PATCH 4/5] Improve platform description and update date picker for mobile compatibility Update replit.md to refine the project overview and fixDateTimePicker mobile viewport issues by implementing a responsive strategy and Radix UI collision detection. Replit-Commit-Author: Agent Replit-Commit-Session-Id: ae4037a0-2a6f-4530-9bac-79b543286bda Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Event-Id: b1fb1922-4125-43d4-9562-e54f011765c7 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/397bca8c-984f-43ff-841a-10897aeb8140/ae4037a0-2a6f-4530-9bac-79b543286bda/ofL5rPP --- replit.md | 47 +++++++++++++---------------------------------- 1 file changed, 13 insertions(+), 34 deletions(-) diff --git a/replit.md b/replit.md index 8d596b7..eddf42e 100644 --- a/replit.md +++ b/replit.md @@ -2,77 +2,56 @@ ## Overview -Social Flow is a comprehensive social media automation platform designed to streamline content creation and publication across Facebook and Instagram. It enables users to manage multiple social media pages, generate AI-powered post content, optimize media for different platform formats, and schedule posts with automated publishing. The platform aims to automate the entire social media content workflow, from creation to publication, utilizing AI for text generation and intelligent media formatting tailored for platform-specific requirements. Key capabilities include multi-photo carousel posts with drag-and-drop reordering, a preview modal for realistic platform rendering, and an integrated media library. The project's ambition is to provide a complete, AI-driven solution for social media content management, significantly reducing manual effort and improving content quality and reach. +Social Flow is a comprehensive AI-powered social media automation platform designed to streamline content creation and publication across Facebook and Instagram. It enables users to manage multiple social media pages, generate AI-powered post content, optimize media for different platform formats, and schedule posts with automated publishing. The platform's ambition is to provide a complete, AI-driven solution for social media content management, significantly reducing manual effort and improving content quality and reach. Key capabilities include multi-photo carousel posts with drag-and-drop reordering, a preview modal for realistic platform rendering, and an integrated media library. ## User Preferences Preferred communication style: Simple, everyday language. -## Recent Changes - -### October 29, 2025 -- **DateTimePicker Mobile Viewport Fix**: Fixed critical display issues where time picker columns were not visible on mobile devices. Problem: Popover could overflow screen edges or be positioned off-viewport on small mobile screens. Solution: Implemented comprehensive responsive strategy with flexible widths (`w-auto min-w-[200px] max-w-[280px]`), centered alignment, and Radix UI collision detection props (`collisionPadding={16}`, `avoidCollisions={true}`, `side="bottom"`). ScrollArea columns use `min-w-[96px] flex-1` (hours) and `min-w-[80px] flex-1` (minutes) for adaptive sizing. Tested and verified on iPhone 12 (390x844), iPhone SE 2nd/3rd gen (375x667), and iPhone SE 1st gen (320x568 - smallest modern iPhone). Both hour and minute columns now reliably visible and functional on all tested mobile viewports. -- **Scheduled Posts Page-Level Filtering Security Fix**: Fixed security vulnerability where users could see occupied dates from all pages in the DateTimePicker, including pages they don't have access to. Added new storage method `getScheduledPostsByPages()` that filters scheduled posts directly in database using SQL WHERE IN clause with authorized page IDs. Modified GET `/api/scheduled-posts` endpoint to use getUserAccessiblePages for standard users (only their assigned pages) and all pages for admins. This eliminates temporary exposure of sensitive data in memory and improves performance by querying only authorized posts from the database. -- **Interactive Calendar with Visual Indicators**: Replaced native datetime-local input with custom DateTimePicker component featuring visual planning aids. Calendar displays occupied dates with red background (bg-red-500/20) to prevent scheduling conflicts. Time selector highlights optimal posting hours (8h, 12h-13h, 18h-20h) with green background (bg-green-500/20) and sparkle emoji to maximize audience engagement. Component includes clear button (X icon) to quickly return to immediate publishing, useEffect synchronization for external state updates, and French locale support via date-fns. Time selector optimized for compactness: ScrollArea height reduced from 240px to 192px (20% smaller), button height set to 36px for touch accessibility, tighter padding and margins throughout. Mobile calendar list still displays today's date first for quick access. -- **Facebook Video Story Publishing Fix**: Fixed critical bug preventing video story publication. Facebook Graph API requires a 3-phase upload process for video stories: (1) START phase - initialize upload session and get `video_id` + `upload_url`, (2) UPLOAD phase - POST video to rupload.facebook.com endpoint with `file_url` header and OAuth authorization, (3) FINISH phase - finalize and publish story with `video_id`. Previous implementation incorrectly attempted direct upload to `/video_stories` endpoint with `file_url` parameter, causing "#100 The parameter upload_phase is required" error. Fixed by implementing proper 3-phase workflow using remote URL upload method (file_url header), avoiding need for binary chunked uploads. - -### October 17, 2025 -- **Docker Deployment Configuration**: Configured Docker Compose for private server deployment with PostgreSQL and application on same network. PostgreSQL exposed on port 4523:4523 for external access. Application runs on internal port 5555 (accessible via Nginx reverse proxy). Both PostgreSQL and app are on nginx_default external network and internal network for communication. Created comprehensive DOCKER.md documentation with setup instructions, network architecture explanation, and troubleshooting guide. - -### October 14, 2025 -- **Publication History Error Display Fix**: Fixed bug where publication history incorrectly displayed persistent errors for posts that failed initially but succeeded on retry. Problem: When a post failed, the `error` field was populated, but when the post was successfully republished, only `publishedAt` and `externalPostId` were updated without clearing the `error` field. Solution: Modified `schedulerService.publishPost()` to set `error: null` when publication succeeds, ensuring error messages are cleared from the history view after successful republication. -- **Publishing Permissions Security Fix**: Fixed critical security vulnerability in POST `/api/posts` endpoint where standard users could publish to ANY page without verification. Added permission check that validates non-admin users can only publish to pages in their `user_page_permissions` list via `getUserAccessiblePages()`. Admins bypass this check and retain full access. Returns 403 Forbidden if user attempts to publish to unauthorized pages. This prevents privilege escalation and ensures proper page-level access control. -- **AI Generation Permissions Fix**: Enabled AI text generation for all authenticated users (previously admin-only). Changed `/api/ai/generate` endpoint from `requireAdmin` to `requireAuth` middleware. Added `getAnyOpenrouterConfig()` method in storage layer to retrieve first available OpenRouter config, enabling shared credentials across all users (same pattern as Cloudinary). Updated `OpenRouterService.generatePostText()` to use shared config instead of per-user lookup. Standard users can now generate AI-powered post text using admin's OpenRouter configuration. -- **Cloudinary Upload Permissions Fix**: Fixed critical bug preventing non-admin users from uploading media. Problem: System searched for user-specific Cloudinary config (only admins can configure). Solution: Added `getAnyCloudinaryConfig()` method in storage layer to retrieve first available config, enabling shared Cloudinary credentials across all users. Updated `cloudinaryService.uploadMedia()` and `deleteMedia()` to use shared config internally while maintaining userId for media ownership. Upload and image editor endpoints now verify shared config exists before processing. Standard users can now upload media successfully using admin's Cloudinary configuration. -- **Android Camera Upload Fix**: Fixed critical Android camera capture bug where uploads failed with 400 error. Android devices send captured files with invalid names (empty, 'blob', etc.) that Multer rejects. Solution: `handleCameraCapture` now detects invalid filenames and creates new File object with generated name `camera-${timestamp}.${extension}` while preserving MIME type. Applied to both new-post and media-upload components. iPhone functionality unaffected. -- **Mobile Performance Optimizations**: Implemented comprehensive mobile speed optimizations for "Nouvelle publication" and "MĂ©diathĂšque" pages. Changes include: (1) Adaptive initial loading - 6 media items on mobile (<768px), 12 on desktop; (2) Optimized thumbnail URLs - replaced `originalUrl` with `facebookFeedUrl` (1080x1080 Cloudinary transformed images) for 70-90% reduction in data transfer while keeping `originalUrl` for zoom/preview quality; (3) Native lazy loading - added `loading="lazy"` attribute to all `` tags for deferred off-screen image loading; (4) Responsive grid layout - 2 columns on mobile, 3 on desktop (sm:grid-cols-3) for better touch targets. Expected impact: Initial load time reduced from 3-5s to <1s on mobile devices. -- **Camera Capture in Media Library**: Added camera button đŸ“· to MediaUpload component, mirroring functionality from new-post page. Mobile users (lg:hidden) can now capture photos/videos directly from device camera and auto-upload to media library. Implementation includes hidden file input with `capture="environment"`, `handleCameraCapture` handler with input value reset (`e.target.value = ''`) to enable repeated captures, and integration with existing `uploadMutation` for seamless cloud storage. -- **Video Publishing for Facebook**: Implemented complete video support for Facebook feed and stories. Added `publishVideoPost()` method using `/videos` endpoint with `file_url` parameter for feed videos, and `publishVideoStory()` using `/video_stories` endpoint for story videos. Modified `publishStory()` to detect video media type and route to appropriate handler. Updated `publishPost()` logic to separate image vs video media filtering and use correct publishing methods. Video preview now uses `