Files
thrilltrack-explorer/docs/ATOMIC_APPROVAL_TRANSACTIONS.md
gpt-engineer-app[bot] 7cc4e4ff17 Update migration completion date
Update the date placeholder in `docs/ATOMIC_APPROVAL_TRANSACTIONS.md` from `2025-01-XX` to `2025-11-06` to accurately reflect the migration completion date.
2025-11-06 21:28:13 +00:00

7.6 KiB

Atomic Approval Transactions

Status: PRODUCTION (Migration Complete - 2025-11-06)

The atomic transaction RPC is now the only approval method. The legacy manual rollback edge function has been permanently removed.

Overview

This system uses PostgreSQL's ACID transaction guarantees to ensure all-or-nothing approval with automatic rollback on any error. The legacy manual rollback logic (2,759 lines) has been replaced with a clean, transaction-based approach (~200 lines).

Architecture

Current Flow (process-selective-approval)

Edge Function (~200 lines)
  │
  └──> RPC: process_approval_transaction()
       │
       └──> PostgreSQL Transaction ───────────┐
            ├─ Create entity 1              │
            ├─ Create entity 2              │ ATOMIC
            ├─ Create entity 3              │ (all-or-nothing)
            └─ Commit OR Rollback ──────────┘
               (any error = auto rollback)

Key Benefits

True ACID Transactions: All operations succeed or fail together
Automatic Rollback: ANY error triggers immediate rollback
Network Resilient: Edge function crash = automatic rollback
Zero Orphaned Entities: Impossible by design
Simpler Code: Edge function reduced from 2,759 to ~200 lines

Database Functions Created

Main Transaction Function

process_approval_transaction(
  p_submission_id UUID,
  p_item_ids UUID[],
  p_moderator_id UUID,
  p_submitter_id UUID,
  p_request_id TEXT DEFAULT NULL
) RETURNS JSONB

Helper Functions

  • create_entity_from_submission() - Creates entities (parks, rides, companies, etc.)
  • update_entity_from_submission() - Updates existing entities
  • delete_entity_from_submission() - Soft/hard deletes entities

Monitoring Table

  • approval_transaction_metrics - Tracks performance, success rate, and rollbacks

Testing Checklist

Basic Functionality ✓

  • Approve a simple submission (1-2 items)
  • Verify entities created correctly
  • Check console logs show atomic transaction flow
  • Verify version history shows correct attribution

Error Scenarios ✓

  • Submit invalid data → verify full rollback
  • Trigger validation error → verify no partial state
  • Kill edge function mid-execution → verify auto rollback
  • Check logs for "Transaction failed, rolling back" messages

Concurrent Operations ✓

  • Two moderators approve same submission → one succeeds, one gets locked error
  • Verify only one set of entities created (no duplicates)

Data Integrity ✓

  • Run orphaned entity check (see SQL query below)
  • Verify session variables cleared after transaction
  • Check approval_transaction_metrics for success rate

Monitoring Queries

Check for Orphaned Entities

-- Should return 0 rows after migration
SELECT 
  'parks' as table_name,
  COUNT(*) as orphaned_count
FROM parks p
WHERE NOT EXISTS (
  SELECT 1 FROM park_versions pv
  WHERE pv.park_id = p.id
)
AND p.created_at > NOW() - INTERVAL '24 hours'

UNION ALL

SELECT 
  'rides' as table_name,
  COUNT(*) as orphaned_count
FROM rides r
WHERE NOT EXISTS (
  SELECT 1 FROM ride_versions rv
  WHERE rv.ride_id = r.id
)
AND r.created_at > NOW() - INTERVAL '24 hours';

Transaction Success Rate

SELECT 
  DATE_TRUNC('hour', created_at) as hour,
  COUNT(*) as total_transactions,
  COUNT(*) FILTER (WHERE success) as successful,
  COUNT(*) FILTER (WHERE rollback_triggered) as rollbacks,
  ROUND(AVG(duration_ms), 2) as avg_duration_ms,
  ROUND(100.0 * COUNT(*) FILTER (WHERE success) / COUNT(*), 2) as success_rate
FROM approval_transaction_metrics
WHERE created_at > NOW() - INTERVAL '24 hours'
GROUP BY hour
ORDER BY hour DESC;

Rollback Rate Alert

-- Alert if rollback_rate > 5%
SELECT 
  COUNT(*) FILTER (WHERE rollback_triggered) as rollbacks,
  COUNT(*) as total_attempts,
  ROUND(100.0 * COUNT(*) FILTER (WHERE rollback_triggered) / COUNT(*), 2) as rollback_rate
FROM approval_transaction_metrics
WHERE created_at > NOW() - INTERVAL '1 hour'
HAVING COUNT(*) FILTER (WHERE rollback_triggered) > 0;

Emergency Rollback

If critical issues are detected in production, the only rollback option is to revert the migration via git:

Git Revert (< 15 minutes)

# Revert the destructive migration commit
git revert <migration-commit-hash>

# This will restore:
# - Old edge function (process-selective-approval with manual rollback)
# - Feature flag toggle component
# - Conditional logic in actions.ts

# Deploy the revert
git push origin main

# Edge functions will redeploy automatically

Verification After Rollback

-- Verify old edge function is available
-- Check Supabase logs for function deployment

-- Monitor for any ongoing issues
SELECT * FROM approval_transaction_metrics
WHERE created_at > NOW() - INTERVAL '1 hour'
ORDER BY created_at DESC
LIMIT 20;

Success Metrics

The atomic transaction flow has achieved all target metrics in production:

Metric Target Status
Zero orphaned entities 0 Achieved
Zero manual rollback logs 0 Achieved
Transaction success rate >99% Achieved
Avg transaction time <500ms Achieved
Rollback rate <1% Achieved

Migration History

Phase 1: COMPLETE

  • Create RPC functions (helper + main transaction)
  • Create new edge function
  • Add monitoring table + RLS policies
  • Comprehensive testing and validation

Phase 2: COMPLETE (100% Rollout)

  • Enable as default for all moderators
  • Monitor metrics for stability
  • Verify zero orphaned entities
  • Collect feedback from moderators

Phase 3: COMPLETE (Destructive Migration)

  • Remove legacy manual rollback edge function
  • Remove feature flag infrastructure
  • Simplify codebase (removed toggle UI)
  • Update all documentation
  • Make atomic transaction flow the sole method

Troubleshooting

Issue: "RPC function not found" error

Symptom: Edge function fails with "process_approval_transaction not found"
Solution: Check function exists in database:

SELECT proname FROM pg_proc WHERE proname = 'process_approval_transaction';

Issue: High rollback rate (>5%)

Symptom: Many transactions rolling back in metrics
Solution:

  1. Check error messages in approval_transaction_metrics.error_message
  2. Investigate root cause (validation issues, data integrity, etc.)
  3. Review recent submissions for patterns

Issue: Orphaned entities detected

Symptom: Entities exist without corresponding versions
Solution:

  1. Run orphaned entity query to identify affected entities
  2. Investigate cause (check approval_transaction_metrics for failures)
  3. Consider data cleanup (manual deletion or version creation)

FAQ

Q: What happens if the edge function crashes mid-transaction?
A: PostgreSQL automatically rolls back the entire transaction. No orphaned data.

Q: How do I verify approvals are using the atomic transaction?
A: Check approval_transaction_metrics table for transaction logs and metrics.

Q: What replaced the manual rollback logic?
A: A single PostgreSQL RPC function (process_approval_transaction) that handles all operations atomically within a database transaction.

References