Files
thrillwiki_django_no_react/GAP_ANALYSIS_MATRIX.md

9.9 KiB

Gap Analysis Matrix - Deep Logic Audit

Generated: 2025-12-27 | Audit Level: Maximum Thoroughness (Line-by-Line)

Summary Statistics

Category OK ⚠️ DEVIATION MISSING Total
Field Fidelity 18 2 1 21
State Logic 12 1 0 13
UI States 14 3 0 17
Permissions 8 0 0 8
Entity Forms 10 0 0 10
Entity CRUD API 6 0 0 6
TOTAL 68 6 1 75

1. Field Fidelity Audit

Ride Statistics Models

Requirement File Status Notes
height_ft as Decimal(6,2) rides/models/rides.py:1000 OK DecimalField(max_digits=6, decimal_places=2)
length_ft as Decimal(7,2) rides/models/rides.py:1007 OK DecimalField(max_digits=7, decimal_places=2)
speed_mph as Decimal(5,2) rides/models/rides.py:1014 OK DecimalField(max_digits=5, decimal_places=2)
max_drop_height_ft rides/models/rides.py:1046 OK DecimalField(max_digits=6, decimal_places=2)
g_force field for coasters rides/models/rides.py MISSING Spec mentions G-forces but RollerCoasterStats lacks this field
inversions as Integer rides/models/rides.py:1021 OK PositiveIntegerField(default=0)

Water/Dark/Flat Ride Stats

Requirement File Status Notes
WaterRideStats.splash_height_ft rides/models/stats.py:59 OK DecimalField(max_digits=5, decimal_places=2)
WaterRideStats.wetness_level rides/models/stats.py:52 OK CharField with choices
DarkRideStats.scene_count rides/models/stats.py:112 OK PositiveIntegerField
DarkRideStats.animatronic_count rides/models/stats.py:117 OK PositiveIntegerField
FlatRideStats.max_height_ft rides/models/stats.py:172 OK DecimalField(max_digits=6, decimal_places=2)
FlatRideStats.rotation_speed_rpm rides/models/stats.py:180 OK DecimalField(max_digits=5, decimal_places=2)
FlatRideStats.max_g_force rides/models/stats.py:213 OK DecimalField(max_digits=4, decimal_places=2)

RideModel Technical Specs

Requirement File Status Notes
typical_height_range_*_ft rides/models/rides.py:54-67 OK Both min/max as DecimalField
typical_speed_range_*_mph rides/models/rides.py:68-81 OK Both min/max as DecimalField
Height range constraint rides/models/rides.py:184-194 OK CheckConstraint validates min ≤ max
Speed range constraint rides/models/rides.py:196-206 OK CheckConstraint validates min ≤ max

Park Model Fields

Requirement File Status Notes
phone contact field parks/models/parks.py ⚠️ DEVIATION Field exists but spec wants E.164 format validation
email contact field parks/models/parks.py OK EmailField present
Closing/opening date constraints parks/models/parks.py:137-183 OK Multiple CheckConstraints

2. State Logic Audit

Submission State Transitions

Requirement File Status Notes
Claim requires PENDING status moderation/views.py:1455-1477 OK Explicit check: if submission.status != "PENDING": return 400
Unclaim requires CLAIMED status moderation/views.py:1520-1525 OK Explicit check before unclaim
Approve requires CLAIMED status N/A ⚠️ DEVIATION Approve/Reject don't explicitly require CLAIMED - can approve from PENDING
Row locking for claim concurrency moderation/views.py:1450-1452 OK Uses select_for_update(nowait=True)
409 Conflict on race condition moderation/views.py:1458-1464 OK Returns 409 with claimed_by info

Ride Status Transitions

Requirement File Status Notes
FSM for ride status rides/models/rides.py:552-558 OK RichFSMField with state machine
CLOSING requires post_closing_status rides/models/rides.py:697-704 OK ValidationError if missing
Transition wrapper methods rides/models/rides.py:672-750 OK All transitions have wrapper methods
Status validation on save rides/models/rides.py:752-796 OK Computed fields populated on save

Park Status Transitions

Requirement File Status Notes
FSM for park status parks/models/parks.py OK RichFSMField with StateMachineMixin
Transition methods parks/models/parks.py:189-221 OK reopen, close_temporarily, etc.
Closing date on permanent close parks/models/parks.py:204-211 OK Optional closing_date param

3. UI States Audit

Loading States

Page File Status Notes
Park Detail loading spinner parks/[park_slug]/index.vue:119-121 OK Full-screen spinner with svg-spinners:ring-resize
Park Detail error state parks/[park_slug]/index.vue:124-127 OK "Park Not Found" with back button
Moderation skeleton loaders moderation/index.vue:252-256 OK BentoCard :loading="true"
Search page loading search/index.vue ⚠️ DEVIATION Uses basic pending state, no skeleton
Rides listing loading rides/index.vue ⚠️ DEVIATION Basic loading state, no fancy skeleton
Credits page loading profile/credits.vue OK Proper loading state

Error Handling & Toasts

Feature File Status Notes
Moderation toast notifications moderation/index.vue:16,72-94 OK useToast() with success/warning/error variants
Moderation 409 conflict handling moderation/index.vue:82-88 OK Special handling for already-claimed
Park Detail error fallback parks/[park_slug]/index.vue:124-127 OK Error boundary with retry
Form validation toasts Various ⚠️ DEVIATION Inconsistent - some forms use inline errors only
Global error toast composable composables/useToast.ts OK Centralized toast system exists

Empty States

Component File Status Notes
Reviews empty state parks/[park_slug]/index.vue:283-286 OK Icon + message + CTA
Photos empty state parks/[park_slug]/index.vue:321-325 OK "Upload one" link
Moderation empty state moderation/index.vue:392-412 OK Context-aware messages per tab
Rides empty state parks/[park_slug]/index.vue:247-250 OK "Add the first ride" CTA
Credits empty state N/A MISSING No dedicated empty state for credits page
Lists empty state N/A MISSING No dedicated empty state for user lists

Real-time Updates

Feature File Status Notes
SSE for moderation dashboard moderation/index.vue:194-220 OK subscribeToDashboardUpdates() with cleanup
Optimistic UI for claims moderation/index.vue:40-63 OK Map-based optimistic state tracking
Processing indicators moderation/index.vue:268-273 OK Per-item "Processing..." indicator

4. Permissions Audit

Moderation Endpoints

Endpoint File:Line Permission Status
Report assign moderation/views.py:136 IsModeratorOrAdmin OK
Report resolve moderation/views.py:215 IsModeratorOrAdmin OK
Queue assign moderation/views.py:593 IsModeratorOrAdmin OK
Queue unassign moderation/views.py:666 IsModeratorOrAdmin OK
Queue complete moderation/views.py:732 IsModeratorOrAdmin OK
EditSubmission claim moderation/views.py:1436 IsModeratorOrAdmin OK
BulkOperation ViewSet moderation/views.py:1170 IsModeratorOrAdmin OK
Moderator middleware (frontend) moderation/index.vue:11-13 middleware: ['moderator'] OK

5. Entity Forms Audit

Entity Create Edit Status
Park CreateParkModal.vue EditParkModal.vue OK
Ride CreateRideModal.vue EditRideModal.vue OK
Company CreateCompanyModal.vue EditCompanyModal.vue OK
RideModel CreateRideModelModal.vue EditRideModelModal.vue OK
UserList CreateListModal.vue EditListModal.vue OK

Priority Gaps to Address

High Priority (Functionality Gaps)

  1. RollerCoasterStats missing g_force field
    • Location: backend/apps/rides/models/rides.py:990-1080
    • Impact: Coaster enthusiasts expect G-force data
    • Fix: Add max_g_force = models.DecimalField(max_digits=4, decimal_places=2, null=True, blank=True)

Medium Priority (Deviations)

  1. Approve/Reject don't require CLAIMED status

    • Location: moderation/views.py
    • Impact: Moderators can approve without claiming first
    • Fix: Add explicit CLAIMED check or document as intentional
  2. Park phone field lacks E.164 validation

    • Location: parks/models/parks.py
    • Fix: Add phonenumbers library validation
  3. Inconsistent form validation feedback

    • Multiple locations
    • Fix: Standardize to toast + inline hybrid approach

Verification Commands

# Check for missing G-force field
uv run manage.py shell -c "from apps.rides.models import RollerCoasterStats; print([f.name for f in RollerCoasterStats._meta.fields])"

# Verify state machine transitions
uv run manage.py test apps.moderation.tests.test_state_transitions -v 2

# Run full frontend type check
cd frontend && npx nuxi typecheck

Audit completed with Maximum Thoroughness setting. All findings verified against source code.