mirror of
				https://github.com/Wan-Video/Wan2.1.git
				synced 2025-11-04 06:15:17 +00:00 
			
		
		
		
	This commit implements Phase 3 of the Wan2.1 PWA, closing all critical integration gaps between frontend, backend, database, and Replicate API. ## Backend Integration ✅ ### Database Writes - Create generation records BEFORE calling Replicate - Store job_id for tracking Replicate predictions - Track progress, status, and completion timestamps - Save video URLs and error messages ### Credit System - Atomic credit deduction using database function deduct_credits() - Automatic refunds on generation failures via refund_credits() - Complete audit trail in credit_transactions table - Transaction logging for all credit operations ### Webhook Handler - Created /api/webhooks/replicate endpoint - HMAC signature verification for security - Automatic status updates from Replicate push notifications - Maps Replicate statuses to application statuses - Triggers refunds for failed generations ### Updated Generation Flow 1. Check user credits before starting 2. Create generation record (status: queued) 3. Start Replicate job and get job_id 4. Update record with job_id (status: processing) 5. Deduct credits atomically 6. Webhook updates status when complete 7. Polling fallback if webhook fails ## Frontend Enhancements ✅ ### Error Handling - Added sonner for beautiful toast notifications - Success/error/loading states with retry actions - User-friendly error messages - Providers component wraps app with Toaster ### Form Validation - Zod schemas for T2V and I2V inputs - Prompt length validation (10-500 chars) - Model and resolution validation - Credit cost calculator ### Credit Management - useCredits hook for real-time credit fetching - Optimistic updates on generation start - Credit refresh functionality - Loading and error states ### Image Upload - Drag-and-drop ImageUpload component - Client-side validation (file type, size) - Image preview functionality - Max 10MB size limit with user feedback - Ready for I2V integration ### Settings Page - Basic settings page structure - Placeholders for Profile, Billing, API Keys - Ready for Phase 4 enhancements ## Database Changes ✅ ### New Migration: 002_credit_system.sql - credit_transactions table with audit trail - deduct_credits() function for atomic operations - add_credits() function for purchases/bonuses - refund_credits() function for failed generations - Added job_id, progress, error_message columns to generations ## Documentation ✅ ### PHASE_3_IMPLEMENTATION.md - Complete implementation guide - Testing checklist (backend, frontend, E2E) - Deployment steps with webhook registration - Known issues and limitations - Metrics to monitor - Phase 4 roadmap ## Files Changed ### Backend (4 files) - apps/api/main.py - Added webhooks router - apps/api/routes/generation.py - Complete rewrite with DB integration - apps/api/routes/webhooks.py - NEW webhook handler - packages/db/migrations/002_credit_system.sql - NEW credit system ### Frontend (7 files) - apps/web/package.json - Added sonner - apps/web/src/app/layout.tsx - Added Providers wrapper - apps/web/src/app/dashboard/settings/page.tsx - NEW settings page - apps/web/src/components/providers.tsx - NEW toast provider - apps/web/src/components/generation/image-upload.tsx - NEW upload component - apps/web/src/lib/hooks/use-credits.ts - NEW credit management hook - apps/web/src/lib/validation/generation.ts - NEW Zod schemas ### Documentation (1 file) - PHASE_3_IMPLEMENTATION.md - NEW comprehensive guide ## Testing Required ### Backend - [ ] Database writes on generation start - [ ] Credit deduction accuracy - [ ] Webhook updates from Replicate - [ ] Refunds on failures ### Frontend - [ ] Toast notifications - [ ] Form validation - [ ] Credit display and warnings - [ ] Image upload ### Integration - [ ] End-to-end generation flow - [ ] Credit deduction → generation → completion - [ ] Webhook vs polling updates ## Next Steps (Phase 4) 1. Payment integration with Stripe 2. Retry logic for failed generations 3. Cancel in-progress generations 4. In-app video player 5. Batch operations 6. Admin panel ## Environment Variables ### New Required Variables - REPLICATE_WEBHOOK_SECRET - For webhook signature verification See PHASE_3_IMPLEMENTATION.md for complete setup instructions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			114 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			PL/PgSQL
		
	
	
	
	
	
			
		
		
	
	
			114 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			PL/PgSQL
		
	
	
	
	
	
-- Add credit transaction log (for audit trail)
 | 
						|
CREATE TABLE IF NOT EXISTS public.credit_transactions (
 | 
						|
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
 | 
						|
  user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
 | 
						|
  amount INTEGER NOT NULL,
 | 
						|
  type TEXT NOT NULL CHECK (type IN ('deduction', 'purchase', 'refund')),
 | 
						|
  generation_id UUID REFERENCES public.generations(id),
 | 
						|
  description TEXT,
 | 
						|
  created_at TIMESTAMPTZ DEFAULT NOW()
 | 
						|
);
 | 
						|
 | 
						|
-- Index for user queries
 | 
						|
CREATE INDEX IF NOT EXISTS idx_credit_transactions_user ON public.credit_transactions(user_id, created_at DESC);
 | 
						|
 | 
						|
-- Enable RLS
 | 
						|
ALTER TABLE public.credit_transactions ENABLE ROW LEVEL SECURITY;
 | 
						|
 | 
						|
CREATE POLICY "Users can view own transactions"
 | 
						|
  ON public.credit_transactions FOR SELECT
 | 
						|
  USING (auth.uid() = user_id);
 | 
						|
 | 
						|
-- Update deduct_credits function to log transaction
 | 
						|
CREATE OR REPLACE FUNCTION deduct_credits(p_user_id UUID, p_amount INTEGER, p_gen_id UUID DEFAULT NULL)
 | 
						|
RETURNS VOID AS $$
 | 
						|
BEGIN
 | 
						|
  -- Deduct credits atomically
 | 
						|
  UPDATE public.users
 | 
						|
  SET credits = credits - p_amount, updated_at = NOW()
 | 
						|
  WHERE id = p_user_id AND credits >= p_amount;
 | 
						|
 | 
						|
  IF NOT FOUND THEN
 | 
						|
    RAISE EXCEPTION 'Insufficient credits';
 | 
						|
  END IF;
 | 
						|
 | 
						|
  -- Log transaction
 | 
						|
  INSERT INTO public.credit_transactions (user_id, amount, type, generation_id, description)
 | 
						|
  VALUES (p_user_id, -p_amount, 'deduction', p_gen_id, 'Video generation');
 | 
						|
END;
 | 
						|
$$ LANGUAGE plpgsql SECURITY DEFINER;
 | 
						|
 | 
						|
-- Function to add credits (for purchases/refunds)
 | 
						|
CREATE OR REPLACE FUNCTION add_credits(p_user_id UUID, p_amount INTEGER, p_type TEXT, p_description TEXT DEFAULT NULL)
 | 
						|
RETURNS VOID AS $$
 | 
						|
BEGIN
 | 
						|
  -- Add credits
 | 
						|
  UPDATE public.users
 | 
						|
  SET credits = credits + p_amount, updated_at = NOW()
 | 
						|
  WHERE id = p_user_id;
 | 
						|
 | 
						|
  IF NOT FOUND THEN
 | 
						|
    RAISE EXCEPTION 'User not found';
 | 
						|
  END IF;
 | 
						|
 | 
						|
  -- Log transaction
 | 
						|
  INSERT INTO public.credit_transactions (user_id, amount, type, description)
 | 
						|
  VALUES (p_user_id, p_amount, p_type, p_description);
 | 
						|
END;
 | 
						|
$$ LANGUAGE plpgsql SECURITY DEFINER;
 | 
						|
 | 
						|
-- Function to refund credits
 | 
						|
CREATE OR REPLACE FUNCTION refund_credits(p_gen_id UUID)
 | 
						|
RETURNS VOID AS $$
 | 
						|
DECLARE
 | 
						|
  v_user_id UUID;
 | 
						|
  v_credits_used INTEGER;
 | 
						|
BEGIN
 | 
						|
  -- Get generation details
 | 
						|
  SELECT user_id, credits_used INTO v_user_id, v_credits_used
 | 
						|
  FROM public.generations
 | 
						|
  WHERE id = p_gen_id;
 | 
						|
 | 
						|
  IF NOT FOUND THEN
 | 
						|
    RAISE EXCEPTION 'Generation not found';
 | 
						|
  END IF;
 | 
						|
 | 
						|
  -- Refund credits
 | 
						|
  UPDATE public.users
 | 
						|
  SET credits = credits + v_credits_used, updated_at = NOW()
 | 
						|
  WHERE id = v_user_id;
 | 
						|
 | 
						|
  -- Log refund transaction
 | 
						|
  INSERT INTO public.credit_transactions (user_id, amount, type, generation_id, description)
 | 
						|
  VALUES (v_user_id, v_credits_used, 'refund', p_gen_id, 'Generation failed - refund');
 | 
						|
END;
 | 
						|
$$ LANGUAGE plpgsql SECURITY DEFINER;
 | 
						|
 | 
						|
-- Add job_id column to generations if not exists
 | 
						|
DO $$
 | 
						|
BEGIN
 | 
						|
  IF NOT EXISTS (SELECT 1 FROM information_schema.columns
 | 
						|
                 WHERE table_name='generations' AND column_name='job_id') THEN
 | 
						|
    ALTER TABLE public.generations ADD COLUMN job_id TEXT;
 | 
						|
    CREATE INDEX idx_generations_job_id ON public.generations(job_id);
 | 
						|
  END IF;
 | 
						|
END $$;
 | 
						|
 | 
						|
-- Add progress column for tracking
 | 
						|
DO $$
 | 
						|
BEGIN
 | 
						|
  IF NOT EXISTS (SELECT 1 FROM information_schema.columns
 | 
						|
                 WHERE table_name='generations' AND column_name='progress') THEN
 | 
						|
    ALTER TABLE public.generations ADD COLUMN progress INTEGER DEFAULT 0;
 | 
						|
  END IF;
 | 
						|
END $$;
 | 
						|
 | 
						|
-- Add error_message column
 | 
						|
DO $$
 | 
						|
BEGIN
 | 
						|
  IF NOT EXISTS (SELECT 1 FROM information_schema.columns
 | 
						|
                 WHERE table_name='generations' AND column_name='error_message') THEN
 | 
						|
    ALTER TABLE public.generations ADD COLUMN error_message TEXT;
 | 
						|
  END IF;
 | 
						|
END $$;
 |