Files
thrilltrack-explorer/docs/SUBMISSION_FLOW.md
gpt-engineer-app[bot] 1a8395f0a0 Update documentation references
Update remaining documentation files to remove references to the old approval flow and feature flags.
2025-11-06 21:23:29 +00:00

6.7 KiB

Entity Submission Flow - CRITICAL SECURITY PATTERN

The Sacred Flow

Every entity creation or edit MUST follow this exact flow:

1. User fills form
   ↓
2. Submission created → moderation queue
   ↓
3. Moderator reviews & approves
   ↓
4. Edge function writes to database (via service role)
   ↓
5. Versioning system captures change
   ↓
6. Public can view live entity

NEVER DO THIS

// Direct database write - BYPASSES EVERYTHING!
await supabase.from('parks').insert(parkData);
await supabase.from('rides').update({ id: rideId }, rideData);

// Even if you're a moderator/admin:
if (isAdmin) {
  await supabase.from('parks').insert(parkData); // STILL WRONG!
}

Why this is blocked:

  • RLS policies explicitly deny INSERT/UPDATE to authenticated users
  • Only the service role (edge functions) can write
  • Edge functions are ONLY triggered by moderation approval

ALWAYS DO THIS

// Import the submission helpers
import { 
  submitParkCreation, 
  submitParkUpdate,
  submitRideCreation,
  submitRideUpdate 
} from '@/lib/entitySubmissionHelpers';

// For new entities:
const result = await submitParkCreation(parkData, user.id);

// For editing existing entities:
const result = await submitParkUpdate(parkId, parkData, user.id);

For React Components

Use the enforced wrappers:

import { enforceParkSubmissionFlow } from '@/lib/entityFormValidation';

// In your component:
const handleSubmit = enforceParkSubmissionFlow(isEditing, park?.id);

<ParkForm
  isEditing={isEditing}
  initialData={park}
  onSubmit={async (data) => {
    await handleSubmit(data, user!.id);
    toast({ title: "Submitted for review" });
  }}
/>

Why This Matters

Security

  • Prevents spam and vandalism
  • Rate-limits submissions via queue system
  • Blocks malicious automated bots

Quality

  • Human review catches errors, duplicates, inappropriate content
  • Maintains high data quality standards

Accountability

  • Full version history with user attribution
  • Every change is tracked and auditable
  • Can rollback any change

Compliance

  • Complete audit trail for legal/regulatory requirements
  • User attribution for all content

For Moderators/Admins

Even moderators must follow the flow:

  1. Create/edit submission through normal UI
  2. It goes to moderation queue
  3. Review your own submission
  4. Approve it

Why?

  • Ensures versioning captures the change
  • Creates audit trail
  • Prevents accidental mistakes

Exception: Only emergency database fixes via SQL editor should bypass this. These should be:

  • Extremely rare
  • Documented in admin_audit_log
  • Followed by manual version creation if needed

Database Protection

RLS Policies

The following tables have explicit denial policies:

  • parks - INSERT/UPDATE blocked for authenticated users
  • rides - INSERT/UPDATE blocked for authenticated users
  • companies - INSERT/UPDATE blocked for authenticated users
  • ride_models - INSERT/UPDATE blocked for authenticated users

Service Role Access

Only these edge functions can write (they use service role):

  • process-selective-approval - Applies approved submissions atomically (PostgreSQL transaction RPC)
  • Direct SQL migrations (admin only)

Versioning Triggers

All entity writes trigger auto_create_entity_version():

  • Captures full entity state
  • Records user who made change
  • Creates diff of what changed
  • Logs to audit trail if user attribution missing

Error Messages

If you see these errors, you're trying to bypass the flow:

Error: new row violates row-level security policy

→ You tried to INSERT/UPDATE directly. Use submission helpers.

Error: permission denied for table parks/rides/companies/ride_models

→ Same issue - use submission helpers.

Testing the Flow

Manual Test:

  1. Create a new park through the UI
  2. Check content_submissions table - should have new row
  3. Check submission_items table - should have park data
  4. Approve via moderation queue
  5. Check parks table - entity should appear
  6. Check entity_versions table - version should be created
  7. Version should have correct changed_by user_id

Automated Test:

// Test that direct writes are blocked
try {
  await supabase.from('parks').insert({ name: 'Test Park' });
  throw new Error('Expected RLS to block this');
} catch (error) {
  // Should get permission denied error
  expect(error.message).toContain('row-level security');
}

// Test that submission flow works
const result = await submitParkCreation(parkData, userId);
expect(result.submitted).toBe(true);

Monitoring

Dashboard Widgets

Check the admin dashboard for:

  • Suspicious Versions - Versions without user attribution
  • Queue Backlog - Submissions waiting too long
  • Flow Violations - Any attempts to bypass the flow

Audit Logs

-- Check for versions without user attribution
SELECT * FROM entity_versions 
WHERE changed_by IS NULL 
ORDER BY changed_at DESC;

-- Check for direct writes (should be none except migrations)
SELECT * FROM admin_audit_log 
WHERE action = 'version_without_user'
ORDER BY created_at DESC;

Common Pitfalls

"I'll just fix this one typo directly"

Even small fixes must go through the flow. Creates version history.

"I'm an admin, I can bypass this"

No. Admins follow the flow. Prevents mistakes and maintains audit trail.

"This is taking too long, I'll do it in SQL editor"

Only for emergencies. Document it. Create manual version if needed.

"I'll bulk import via CSV"

Bulk imports should:

  1. Create submissions programmatically
  2. Auto-approve them if from trusted source
  3. Still trigger versioning

Questions?

Q: What if I need to bulk import 1000 parks? A: Create submissions programmatically, set status='approved', let edge function process them.

Q: What if there's an emergency typo on homepage? A: Make the fix via submission → have another mod approve immediately. Takes <1 minute.

Q: What if the moderation queue is broken? A: Fix the queue. Don't bypass the flow. That creates worse problems.

Q: Can I use the service role key directly? A: Only in edge functions. Never in client-side code. Never for routine edits.

  • src/lib/entitySubmissionHelpers.ts - Core submission functions
  • src/lib/entityFormValidation.ts - Enforced wrappers
  • supabase/functions/process-selective-approval/index.ts - Atomic transaction RPC approval processor
  • src/components/admin/*Form.tsx - Form components using the flow
  • docs/ATOMIC_APPROVAL_TRANSACTIONS.md - Atomic transaction RPC documentation

Update History

  • 2025-01-XX: Added explicit RLS denial policies
  • 2025-01-XX: Added versioning for photos table
  • 2025-01-XX: Added user attribution to edge function
  • 2025-01-XX: Created this documentation