Files
thrilltrack-explorer/docs/moderation/SUBMISSION_PATTERNS.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

7.1 KiB

Submission Patterns & Guidelines

Overview

This document outlines the patterns and best practices for working with submissions in the moderation queue system.

Submission Types

1. Content Submissions (content_submissions)

When to use:

  • Creating or updating parks, rides, companies, ride models
  • Multi-item submissions with dependencies
  • Submissions requiring moderator review before going live

Data Flow:

User Form → validateEntityData() → createSubmission() 
  → content_submissions table 
  → submission_items table (with dependencies)
  → Moderation Queue
  → Approval → process-selective-approval edge function (atomic transaction RPC)
  → Live entities created (all-or-nothing via PostgreSQL transaction)

Example:

// Creating a park with operator dependency
const { success } = await createParkSubmission({
  name: "Cedar Point",
  park_type: "theme_park",
  operator_id: "new_operator_123", // References another item in same submission
});

2. Photo Submissions (photo_submissions)

When to use:

  • User uploading photos to existing entities
  • Photos require moderation but entity already exists

Data Flow:

UppyPhotoSubmissionUpload 
  → Cloudflare Direct Upload
  → photo_submissions + photo_submission_items tables
  → Moderation Queue
  → Approval → Photos linked to entity

Key Requirements:

  • Must be linked to parent content_submissions for queue integration
  • Caption and title sanitized (plain text only, no HTML)
  • Maximum 10 photos per submission

3. Reviews (reviews)

When to use:

  • User reviewing a park or ride
  • Rating with optional text content

Data Flow:

ReviewForm 
  → reviews table + content_submissions (NEW)
  → Moderation Queue
  → Approval → Review goes live

Sanitization:

  • All review content is plain text (HTML stripped)
  • Maximum 5000 characters
  • Rating validation (0.5-5.0 scale)

When to Use Each Table

Use content_submissions when:

Creating new entities (parks, rides, companies) Updating existing entities Submissions have multi-item dependencies Need moderator review before data goes live

Use Specialized Tables when:

Photos: Entity exists, just adding media (photo_submissions) Reviews: User feedback on existing entity (reviews + content_submissions) Technical Specs: Belongs to specific entity (ride_technical_specifications)

Validation Requirements

All Submissions Must:

  1. Pass Zod schema validation (entityValidationSchemas.ts)
  2. Have proper slug generation (unique, URL-safe)
  3. Include source URLs when applicable
  4. Pass duplicate detection checks

Entity-Specific Requirements:

Parks:

  • Valid park_type enum
  • Valid location data (country required)
  • Opening date format validation

Rides:

  • Must reference valid park_id
  • Valid ride_type enum
  • Opening date validation

Companies:

  • Valid company_type enum
  • Country code validation
  • Founded year range check

Dependency Resolution

Dependency Types:

  1. Same-submission dependencies: New park references new operator (both in queue)
  2. Existing entity dependencies: New ride references existing park
  3. Multi-level dependencies: Ride → Park → Operator → Owner (4 levels)

Resolution Order:

Dependencies are resolved using topological sorting:

1. Load all items in submission
2. Build dependency graph
3. Sort topologically (parents before children)
4. Process in order

Example:

Submission contains:
- Item A: Operator (no dependencies)
- Item B: Park (depends on A)
- Item C: Ride (depends on B)

Processing order: A → B → C

Best Practices

DO:

Use existing entities when possible (avoid duplicates) Provide source URLs for verifiability Write clear submission notes for moderators Validate data on client-side before submission Use type guards when working with SubmissionItemData

DON'T:

Store JSON blobs in SQL columns Skip validation to "speed up" submissions Create dependencies to non-existent entities Submit without source verification Bypass moderation queue (security risk)

Adding New Submission Types

Steps:

  1. Create type definition in src/types/moderation.ts
  2. Add type guard to src/lib/moderation/typeGuards.ts
  3. Create validation schema in src/lib/entityValidationSchemas.ts
  4. Add submission helper in src/lib/entitySubmissionHelpers.ts
  5. Update useModerationQueueManager query to fetch new type
  6. Create renderer component (optional, for complex UI)
  7. Add tests for new type

Example: Adding "Event" Submission Type

// 1. Type definition (moderation.ts)
export interface EventItemData {
  event_id?: string;
  name: string;
  park_id: string;
  start_date: string;
  end_date: string;
}

export type SubmissionItemData = 
  | ParkItemData 
  | RideItemData
  | EventItemData; // Add here

// 2. Type guard (typeGuards.ts)
export function isEventItemData(data: SubmissionItemData): data is EventItemData {
  return 'start_date' in data && 'end_date' in data;
}

// 3. Validation (entityValidationSchemas.ts)
const eventSchema = z.object({
  name: z.string().min(1).max(200),
  park_id: z.string().uuid(),
  start_date: z.string().datetime(),
  end_date: z.string().datetime(),
});

// 4. Submission helper (entitySubmissionHelpers.ts)
export async function createEventSubmission(eventData: EventFormData) {
  // Validation, submission creation logic
}

// 5. Update queue query to include events
// (already handles all content_submissions)

// 6. Optional: Create EventSubmissionDisplay component
// 7. Add tests

Migration Checklist

When migrating legacy code to this pattern:

  • Remove direct database writes (use submission helpers)
  • Add validation schemas
  • Update to use SubmissionItemData types
  • Add type guards where needed
  • Test dependency resolution
  • Verify sanitization is applied
  • Update documentation

Security Considerations

Input Validation:

  • Server-side validation is mandatory (Zod schemas)
  • Client-side validation for UX only
  • Never trust user input - always validate and sanitize

Sanitization:

  • HTML stripped from user text (use rehype-sanitize)
  • URLs validated and optionally stripped
  • File uploads validated (type, size, count)
  • SQL injection prevented (Supabase parameterized queries)

Access Control:

  • Only moderators can approve/reject
  • Users can only submit, not self-approve
  • RLS policies enforce row-level security
  • Lock system prevents concurrent modifications

Troubleshooting

Common Issues:

"Dependency not found" → Check if parent entity exists in database or in same submission

"Validation failed" → Check Zod schema, ensure all required fields present

"Duplicate slug" → Slug generation collided, system will auto-increment

"Lock expired" → Moderator must re-claim submission to continue

"Permission denied" → Check user role (must be moderator/admin)

References

  • See ARCHITECTURE.md for system design
  • See COMPONENTS.md for UI component usage
  • See ../IMPLEMENTATION_COMPLETE.md for recent changes