mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-29 06:26:59 -05:00
9.9 KiB
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)
RollerCoasterStatsmissingg_forcefield- 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)
- Location:
Medium Priority (Deviations)
-
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
- Location:
-
Park phone field lacks E.164 validation
- Location:
parks/models/parks.py - Fix: Add
phonenumberslibrary validation
- Location:
-
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.