mirror of
https://github.com/Wan-Video/Wan2.1.git
synced 2025-11-02 21:42:16 +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 $$;
|