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.
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 entitiesdelete_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_metricsfor 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:
- Check error messages in
approval_transaction_metrics.error_message - Investigate root cause (validation issues, data integrity, etc.)
- Review recent submissions for patterns
Issue: Orphaned entities detected
Symptom: Entities exist without corresponding versions
Solution:
- Run orphaned entity query to identify affected entities
- Investigate cause (check approval_transaction_metrics for failures)
- 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.