Refactor payment flow to use database triggers (Clean Architecture)
BREAKING CHANGE: Complete refactor of payment handling New Architecture: 1. pakasir-webhook (120 lines -> was 535 lines) - Only verifies signature and updates order status - Removed: SMTP, email templates, notification logic 2. Database Trigger (NEW) - Automatically fires when payment_status = 'paid' - Calls handle-order-paid edge function - Works for webhook AND manual admin updates 3. handle-order-paid (NEW edge function) - Grants user access for products - Creates Google Meet events for consulting - Sends notifications via send-email-v2 - Triggers webhooks Benefits: - Single Responsibility: Each function has one clear purpose - Trigger works for both webhook and manual admin actions - Easier to debug and maintain - Reusable notification system Migration required: Run 20241223_payment_trigger.sql 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
93
supabase/migrations/20241223_payment_trigger.sql
Normal file
93
supabase/migrations/20241223_payment_trigger.sql
Normal file
@@ -0,0 +1,93 @@
|
||||
-- ============================================================================
|
||||
-- Payment Trigger Architecture
|
||||
-- ============================================================================
|
||||
-- This refactors the payment flow to use database triggers instead of
|
||||
-- handling everything in the webhook function.
|
||||
--
|
||||
-- Flow:
|
||||
-- 1. pakasir-webhook or admin updates order.payment_status = 'paid'
|
||||
-- 2. Trigger fires -> calls handle_paid_order() function
|
||||
-- 3. handle_paid_order() calls handle-order-paid edge function
|
||||
-- 4. Edge function handles: access grants, notifications, meet links
|
||||
-- ============================================================================
|
||||
|
||||
-- Enable pg_net extension for HTTP calls from PostgreSQL
|
||||
CREATE EXTENSION IF NOT EXISTS pg_net;
|
||||
|
||||
-- ============================================================================
|
||||
-- Function: handle_paid_order
|
||||
-- Purpose: Called by trigger when order payment_status becomes 'paid'
|
||||
-- Calls the edge function to handle all post-payment actions
|
||||
-- ============================================================================
|
||||
CREATE OR REPLACE FUNCTION handle_paid_order()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
edge_function_url TEXT;
|
||||
edge_function_response TEXT;
|
||||
order_data JSON;
|
||||
BEGIN
|
||||
-- Only proceed if payment_status changed to 'paid'
|
||||
IF (NEW.payment_status != 'paid' OR OLD.payment_status = 'paid') THEN
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
|
||||
-- Log the payment event
|
||||
RAISE NOTICE 'Order % payment status changed to paid', NEW.id;
|
||||
|
||||
-- Get the edge function URL from environment
|
||||
edge_function_url := current_setting('app.base_url', true) || '/functions/v1/handle-order-paid';
|
||||
|
||||
-- Prepare order data
|
||||
order_data := json_build_object(
|
||||
'order_id', NEW.id,
|
||||
'user_id', NEW.user_id,
|
||||
'total_amount', NEW.total_amount,
|
||||
'payment_method', NEW.payment_method,
|
||||
'payment_provider', NEW.payment_provider
|
||||
);
|
||||
|
||||
-- Call the edge function asynchronously via pg_net
|
||||
-- We use pg_net to avoid blocking the transaction
|
||||
PERFORM net.http_post(
|
||||
url := edge_function_url,
|
||||
headers := json_build_object(
|
||||
'Content-Type', 'application/json',
|
||||
'Authorization', 'Bearer ' || current_setting('app.service_role_key', true)
|
||||
),
|
||||
body := order_data
|
||||
);
|
||||
|
||||
RAISE NOTICE 'Called handle-order-paid for order %', NEW.id;
|
||||
|
||||
RETURN NEW;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
-- Log error but don't fail the transaction
|
||||
RAISE WARNING 'Failed to call handle-order-paid for order %: %', NEW.id, SQLERRM;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- ============================================================================
|
||||
-- Trigger: on_order_paid
|
||||
-- Purpose: Fires handle_paid_order() when order payment status changes
|
||||
-- ============================================================================
|
||||
DROP TRIGGER IF EXISTS on_order_paid ON orders;
|
||||
|
||||
CREATE TRIGGER on_order_paid
|
||||
AFTER UPDATE ON orders
|
||||
FOR EACH ROW
|
||||
WHEN (NEW.payment_status = 'paid' AND OLD.payment_status IS DISTINCT FROM NEW.payment_status)
|
||||
EXECUTE FUNCTION handle_paid_order();
|
||||
|
||||
-- ============================================================================
|
||||
-- Comments for documentation
|
||||
-- ============================================================================
|
||||
COMMENT ON FUNCTION handle_paid_order() IS 'Triggered when order payment_status becomes "paid". Calls handle-order-paid edge function to handle access grants, notifications, and Meet link creation.';
|
||||
COMMENT ON TRIGGER on_order_paid ON orders IS 'Fires handle_paid_order() function when payment status changes to paid';
|
||||
|
||||
-- ============================================================================
|
||||
-- Grant necessary permissions
|
||||
-- ============================================================================
|
||||
GRANT EXECUTE ON FUNCTION handle_paid_order() TO postgres;
|
||||
GRANT USAGE ON SCHEMA net TO postgres;
|
||||
Reference in New Issue
Block a user