mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 16:51:07 -05:00
Compare commits
1 Commits
nuxt
...
february20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8900716215 |
8
.gitignore
vendored
8
.gitignore
vendored
@@ -353,7 +353,8 @@ cython_debug/
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
Icon
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
@@ -373,3 +374,8 @@ Icon
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
backend/.env
|
||||
.env
|
||||
frontend
|
||||
uv.lock
|
||||
.django_tailwind_cli/tailwindcss-macos-arm64-4.1.13
|
||||
|
||||
123
FRONTEND_IMPLEMENTATION_PLAN.md
Normal file
123
FRONTEND_IMPLEMENTATION_PLAN.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# Frontend Implementation Plan - Phase 1 Critical Components
|
||||
|
||||
## Current State Analysis ✅
|
||||
|
||||
### Completed Components
|
||||
- **Authentication System** - Modal-based auth with social integration ✅
|
||||
- **Toast Notification System** - Advanced toast system with animations ✅
|
||||
- **Theme Management** - Working well ✅
|
||||
- **Header Navigation** - Enhanced with modal integration ✅
|
||||
- **Base Template Structure** - Solid foundation ✅
|
||||
- **Basic Alpine.js Components** - Core components implemented ✅
|
||||
|
||||
### Missing Critical Components (Phase 1 - High Priority)
|
||||
|
||||
## 1. Enhanced Search with Autocomplete 🎯
|
||||
**Current**: Basic search exists but lacks autocomplete and advanced features
|
||||
**Needed**:
|
||||
- Debounced search with API integration
|
||||
- Search suggestions dropdown UI
|
||||
- Search result highlighting
|
||||
- Keyboard navigation for search suggestions
|
||||
- Recent searches and popular searches
|
||||
|
||||
## 2. Enhanced Park/Ride Cards 🎯
|
||||
**Current**: Basic card components exist
|
||||
**Needed**:
|
||||
- Sophisticated hover effects and animations
|
||||
- Card interaction states (hover, focus, active)
|
||||
- Loading states for card images
|
||||
- Card action buttons (favorite, share, etc.)
|
||||
- Image lazy loading and error handling
|
||||
|
||||
## 3. User Profile Management 🎯
|
||||
**Current**: Basic profile pages exist
|
||||
**Needed**:
|
||||
- Comprehensive profile editing interface
|
||||
- Avatar upload with preview functionality
|
||||
- Profile sections (basic info, preferences, privacy)
|
||||
- Form validation and error handling
|
||||
- Settings persistence
|
||||
|
||||
## 4. Advanced Filtering System 🎯
|
||||
**Current**: Basic filtering exists
|
||||
**Needed**:
|
||||
- Multi-select filter components
|
||||
- Range slider filters
|
||||
- Date picker filters
|
||||
- URL state synchronization for filters
|
||||
- Filter presets and saved searches
|
||||
|
||||
## 5. Loading States & Skeletons 🎯
|
||||
**Current**: Basic loading indicators
|
||||
**Needed**:
|
||||
- Skeleton loading components
|
||||
- Loading spinners and indicators
|
||||
- Optimistic updates
|
||||
- Loading states for forms and buttons
|
||||
|
||||
## Implementation Priority Order
|
||||
|
||||
### Week 1: Core Interactive Components
|
||||
1. **Enhanced Search Component** (2-3 days)
|
||||
2. **Advanced Card Components** (2-3 days)
|
||||
3. **Loading States System** (1-2 days)
|
||||
|
||||
### Week 2: User Experience Features
|
||||
1. **User Profile Management** (3-4 days)
|
||||
2. **Advanced Filtering System** (3-4 days)
|
||||
|
||||
## Technical Approach
|
||||
|
||||
### 1. Enhanced Search Component
|
||||
```javascript
|
||||
Alpine.data('advancedSearch', () => ({
|
||||
query: '',
|
||||
suggestions: [],
|
||||
recentSearches: [],
|
||||
popularSearches: [],
|
||||
loading: false,
|
||||
showSuggestions: false,
|
||||
selectedIndex: -1,
|
||||
debounceTimer: null,
|
||||
|
||||
// Implementation details...
|
||||
}))
|
||||
```
|
||||
|
||||
### 2. Enhanced Card Component
|
||||
```javascript
|
||||
Alpine.data('enhancedCard', (cardData) => ({
|
||||
data: cardData,
|
||||
imageLoaded: false,
|
||||
imageError: false,
|
||||
favorited: false,
|
||||
|
||||
// Hover effects, animations, interactions
|
||||
}))
|
||||
```
|
||||
|
||||
### 3. Skeleton Loading System
|
||||
```html
|
||||
<!-- Skeleton templates for different content types -->
|
||||
<div class="skeleton-card">
|
||||
<div class="skeleton-image"></div>
|
||||
<div class="skeleton-text"></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Success Metrics
|
||||
- Search response time < 200ms
|
||||
- Card interactions feel smooth (60fps)
|
||||
- Loading states provide clear feedback
|
||||
- User profile updates work seamlessly
|
||||
- Filtering provides instant feedback
|
||||
|
||||
## Next Steps
|
||||
1. Start with Enhanced Search Component implementation
|
||||
2. Create comprehensive card component system
|
||||
3. Implement skeleton loading system
|
||||
4. Build user profile management interface
|
||||
5. Create advanced filtering system
|
||||
|
||||
This plan focuses on the most impactful user experience improvements that will bring the Django frontend to parity with the React implementation.
|
||||
@@ -0,0 +1,89 @@
|
||||
# Generated by Django 5.2.6 on 2025-09-20 13:40
|
||||
|
||||
import pgtrigger.compiler
|
||||
import pgtrigger.migrations
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("accounts", "0002_remove_toplistitem_insert_insert_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="toplist",
|
||||
name="insert_insert",
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="toplist",
|
||||
name="update_update",
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="toplistitem",
|
||||
name="insert_insert",
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="toplistitem",
|
||||
name="update_update",
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="toplist",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "accounts_toplistevent" ("category", "created_at", "description", "id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "title", "updated_at", "user_id") VALUES (NEW."category", NEW."created_at", NEW."description", NEW."id", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."title", NEW."updated_at", NEW."user_id"); RETURN NULL;',
|
||||
hash="0b9e68b3aa0d3fb8f50bd832b99b70201d44aa11",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_26546",
|
||||
table="accounts_toplist",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="toplist",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "accounts_toplistevent" ("category", "created_at", "description", "id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "title", "updated_at", "user_id") VALUES (NEW."category", NEW."created_at", NEW."description", NEW."id", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."title", NEW."updated_at", NEW."user_id"); RETURN NULL;',
|
||||
hash="3ae1293b8b1fe574bac9f388b60d19613347931e",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_84849",
|
||||
table="accounts_toplist",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="toplistitem",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "accounts_toplistitemevent" ("content_type_id", "created_at", "id", "notes", "object_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "rank", "top_list_id", "updated_at") VALUES (NEW."content_type_id", NEW."created_at", NEW."id", NEW."notes", NEW."object_id", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."rank", NEW."top_list_id", NEW."updated_at"); RETURN NULL;',
|
||||
hash="1091ef1cc7668e112916df0c12f222bd25cfe921",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_56dfc",
|
||||
table="accounts_toplistitem",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="toplistitem",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "accounts_toplistitemevent" ("content_type_id", "created_at", "id", "notes", "object_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "rank", "top_list_id", "updated_at") VALUES (NEW."content_type_id", NEW."created_at", NEW."id", NEW."notes", NEW."object_id", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."rank", NEW."top_list_id", NEW."updated_at"); RETURN NULL;',
|
||||
hash="81227a3b4af9432d2b868cd8680bee7896da8acc",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_2b6e3",
|
||||
table="accounts_toplistitem",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
1
backend/.django_tailwind_cli/source.css
Normal file
1
backend/.django_tailwind_cli/source.css
Normal file
@@ -0,0 +1 @@
|
||||
@import "tailwindcss";
|
||||
BIN
backend/.django_tailwind_cli/tailwindcss-macos-arm64-4.1.12
Executable file
BIN
backend/.django_tailwind_cli/tailwindcss-macos-arm64-4.1.12
Executable file
Binary file not shown.
11421
backend/logs/performance.log.1
Normal file
11421
backend/logs/performance.log.1
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,21 @@
|
||||
# Active Context
|
||||
|
||||
## Current Focus
|
||||
- Moderation system development and enhancement
|
||||
- Dashboard interface improvements
|
||||
- Submission review workflow
|
||||
- Database schema synchronization and fixes
|
||||
- Parks model and pghistory integration
|
||||
- Ensuring model-database consistency
|
||||
|
||||
## Recent Changes
|
||||
Working on moderation system components:
|
||||
- Dashboard interface
|
||||
- Submission list views
|
||||
- Moderation navigation
|
||||
- Content review workflow
|
||||
Fixed critical database schema mismatch in parks app:
|
||||
- Updated Park model to include operator and property_owner fields
|
||||
- Added missing owner_id column to parks_parkevent table
|
||||
- Fixed pghistory triggers that were failing due to missing columns
|
||||
- Resolved park detail page errors (parks/magic-kingdom/ now working)
|
||||
|
||||
### Schema Updates Made
|
||||
- parks/models.py: Added operator and property_owner ForeignKey fields
|
||||
- parks/migrations/0006_auto_20250920_0944.py: Added owner_id column to parks_parkevent table
|
||||
- Database now properly supports all three ownership relationships: owner, operator, property_owner
|
||||
|
||||
## Active Files
|
||||
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
# Generated by Django 5.2.6 on 2025-09-20 13:40
|
||||
|
||||
import pgtrigger.compiler
|
||||
import pgtrigger.migrations
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("companies", "0002_alter_company_id_alter_manufacturer_id"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="company",
|
||||
name="insert_insert",
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="company",
|
||||
name="update_update",
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="manufacturer",
|
||||
name="insert_insert",
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="manufacturer",
|
||||
name="update_update",
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="company",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "companies_companyevent" ("created_at", "description", "headquarters", "id", "name", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "slug", "total_parks", "total_rides", "updated_at", "website") VALUES (NEW."created_at", NEW."description", NEW."headquarters", NEW."id", NEW."name", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."slug", NEW."total_parks", NEW."total_rides", NEW."updated_at", NEW."website"); RETURN NULL;',
|
||||
hash="413671b13a748fb5f1acd57e8ec4af12ad7ae215",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_a4101",
|
||||
table="companies_company",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="company",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "companies_companyevent" ("created_at", "description", "headquarters", "id", "name", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "slug", "total_parks", "total_rides", "updated_at", "website") VALUES (NEW."created_at", NEW."description", NEW."headquarters", NEW."id", NEW."name", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."slug", NEW."total_parks", NEW."total_rides", NEW."updated_at", NEW."website"); RETURN NULL;',
|
||||
hash="ee3eff1c96e46769347b8463d527668b7ece63c4",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_3d5ae",
|
||||
table="companies_company",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="manufacturer",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "companies_manufacturerevent" ("created_at", "description", "headquarters", "id", "name", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "slug", "total_rides", "total_roller_coasters", "updated_at", "website") VALUES (NEW."created_at", NEW."description", NEW."headquarters", NEW."id", NEW."name", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."slug", NEW."total_rides", NEW."total_roller_coasters", NEW."updated_at", NEW."website"); RETURN NULL;',
|
||||
hash="ac3c4c31aa8dffe569154454a6c4479d189c0f64",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_5c0b6",
|
||||
table="companies_manufacturer",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="manufacturer",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "companies_manufacturerevent" ("created_at", "description", "headquarters", "id", "name", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "slug", "total_rides", "total_roller_coasters", "updated_at", "website") VALUES (NEW."created_at", NEW."description", NEW."headquarters", NEW."id", NEW."name", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."slug", NEW."total_rides", NEW."total_roller_coasters", NEW."updated_at", NEW."website"); RETURN NULL;',
|
||||
hash="c46f36f5811cd843ff61eab3ae77624ae2e69f60",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_81971",
|
||||
table="companies_manufacturer",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,52 @@
|
||||
# Generated by Django 5.2.6 on 2025-09-20 13:40
|
||||
|
||||
import pgtrigger.compiler
|
||||
import pgtrigger.migrations
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("designers", "0002_alter_designer_id"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="designer",
|
||||
name="insert_insert",
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="designer",
|
||||
name="update_update",
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="designer",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "designers_designerevent" ("created_at", "description", "founded_date", "headquarters", "id", "name", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "slug", "updated_at", "website") VALUES (NEW."created_at", NEW."description", NEW."founded_date", NEW."headquarters", NEW."id", NEW."name", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."slug", NEW."updated_at", NEW."website"); RETURN NULL;',
|
||||
hash="876eaa3e1c7cf234f03cc706fa4e5e508ed780db",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_9be65",
|
||||
table="designers_designer",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="designer",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "designers_designerevent" ("created_at", "description", "founded_date", "headquarters", "id", "name", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "slug", "updated_at", "website") VALUES (NEW."created_at", NEW."description", NEW."founded_date", NEW."headquarters", NEW."id", NEW."name", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."slug", NEW."updated_at", NEW."website"); RETURN NULL;',
|
||||
hash="edb092b6a122ca5827740a9afcdc6a885fe69c1c",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_b5f91",
|
||||
table="designers_designer",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,52 @@
|
||||
# Generated by Django 5.2.6 on 2025-09-20 13:40
|
||||
|
||||
import pgtrigger.compiler
|
||||
import pgtrigger.migrations
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("email_service", "0002_alter_emailconfiguration_id"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="emailconfiguration",
|
||||
name="insert_insert",
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="emailconfiguration",
|
||||
name="update_update",
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="emailconfiguration",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "email_service_emailconfigurationevent" ("api_key", "created_at", "from_email", "from_name", "id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "reply_to", "site_id", "updated_at") VALUES (NEW."api_key", NEW."created_at", NEW."from_email", NEW."from_name", NEW."id", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."reply_to", NEW."site_id", NEW."updated_at"); RETURN NULL;',
|
||||
hash="f19f3c7f7d904d5f850a2ff1e0bf1312e855c8c0",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_08c59",
|
||||
table="email_service_emailconfiguration",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="emailconfiguration",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "email_service_emailconfigurationevent" ("api_key", "created_at", "from_email", "from_name", "id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "reply_to", "site_id", "updated_at") VALUES (NEW."api_key", NEW."created_at", NEW."from_email", NEW."from_name", NEW."id", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."reply_to", NEW."site_id", NEW."updated_at"); RETURN NULL;',
|
||||
hash="e445521baf2cfb51379b2a6be550b4a638d60202",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_992a4",
|
||||
table="email_service_emailconfiguration",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,52 @@
|
||||
# Generated by Django 5.2.6 on 2025-09-20 13:40
|
||||
|
||||
import pgtrigger.compiler
|
||||
import pgtrigger.migrations
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("location", "0002_alter_location_id"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="location",
|
||||
name="insert_insert",
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="location",
|
||||
name="update_update",
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="location",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "location_locationevent" ("city", "content_type_id", "country", "created_at", "id", "latitude", "location_type", "longitude", "name", "object_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "point", "postal_code", "state", "street_address", "updated_at") VALUES (NEW."city", NEW."content_type_id", NEW."country", NEW."created_at", NEW."id", NEW."latitude", NEW."location_type", NEW."longitude", NEW."name", NEW."object_id", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."point", NEW."postal_code", NEW."state", NEW."street_address", NEW."updated_at"); RETURN NULL;',
|
||||
hash="8a8f00869cfcaa1a23ab29b3d855e83602172c67",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_98cd4",
|
||||
table="location_location",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="location",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "location_locationevent" ("city", "content_type_id", "country", "created_at", "id", "latitude", "location_type", "longitude", "name", "object_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "point", "postal_code", "state", "street_address", "updated_at") VALUES (NEW."city", NEW."content_type_id", NEW."country", NEW."created_at", NEW."id", NEW."latitude", NEW."location_type", NEW."longitude", NEW."name", NEW."object_id", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."point", NEW."postal_code", NEW."state", NEW."street_address", NEW."updated_at"); RETURN NULL;',
|
||||
hash="f3378cb26a5d88aa82c8fae016d46037b530de90",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_471d2",
|
||||
table="location_location",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -6,7 +6,7 @@ import sys
|
||||
|
||||
def main():
|
||||
"""Run administrative tasks."""
|
||||
os***REMOVED***iron.setdefault("DJANGO_SETTINGS_MODULE", "thrillwiki.settings")
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "thrillwiki.settings")
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
|
||||
52
media/migrations/0003_remove_photo_insert_insert_and_more.py
Normal file
52
media/migrations/0003_remove_photo_insert_insert_and_more.py
Normal file
@@ -0,0 +1,52 @@
|
||||
# Generated by Django 5.2.6 on 2025-09-20 13:40
|
||||
|
||||
import pgtrigger.compiler
|
||||
import pgtrigger.migrations
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("media", "0002_alter_photo_id"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="photo",
|
||||
name="insert_insert",
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="photo",
|
||||
name="update_update",
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="photo",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "media_photoevent" ("alt_text", "caption", "content_type_id", "created_at", "date_taken", "id", "image", "is_approved", "is_primary", "object_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "updated_at", "uploaded_by_id") VALUES (NEW."alt_text", NEW."caption", NEW."content_type_id", NEW."created_at", NEW."date_taken", NEW."id", NEW."image", NEW."is_approved", NEW."is_primary", NEW."object_id", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."updated_at", NEW."uploaded_by_id"); RETURN NULL;',
|
||||
hash="c75cf37b6fac8d5593598ba2af194f1f9a692838",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_e1ca0",
|
||||
table="media_photo",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="photo",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "media_photoevent" ("alt_text", "caption", "content_type_id", "created_at", "date_taken", "id", "image", "is_approved", "is_primary", "object_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "updated_at", "uploaded_by_id") VALUES (NEW."alt_text", NEW."caption", NEW."content_type_id", NEW."created_at", NEW."date_taken", NEW."id", NEW."image", NEW."is_approved", NEW."is_primary", NEW."object_id", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."updated_at", NEW."uploaded_by_id"); RETURN NULL;',
|
||||
hash="09d9b3bda4d950d7a7104c8f013a93d05025da72",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_6ff7d",
|
||||
table="media_photo",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,89 @@
|
||||
# Generated by Django 5.2.6 on 2025-09-20 13:40
|
||||
|
||||
import pgtrigger.compiler
|
||||
import pgtrigger.migrations
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("moderation", "0002_remove_editsubmission_insert_insert_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="editsubmission",
|
||||
name="insert_insert",
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="editsubmission",
|
||||
name="update_update",
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="photosubmission",
|
||||
name="insert_insert",
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="photosubmission",
|
||||
name="update_update",
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="editsubmission",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "moderation_editsubmissionevent" ("changes", "content_type_id", "created_at", "handled_at", "handled_by_id", "id", "moderator_changes", "notes", "object_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "reason", "source", "status", "submission_type", "updated_at", "user_id") VALUES (NEW."changes", NEW."content_type_id", NEW."created_at", NEW."handled_at", NEW."handled_by_id", NEW."id", NEW."moderator_changes", NEW."notes", NEW."object_id", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."reason", NEW."source", NEW."status", NEW."submission_type", NEW."updated_at", NEW."user_id"); RETURN NULL;',
|
||||
hash="0e394e419ba234dd23cb0f4f6567611ad71f2a38",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_2c796",
|
||||
table="moderation_editsubmission",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="editsubmission",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "moderation_editsubmissionevent" ("changes", "content_type_id", "created_at", "handled_at", "handled_by_id", "id", "moderator_changes", "notes", "object_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "reason", "source", "status", "submission_type", "updated_at", "user_id") VALUES (NEW."changes", NEW."content_type_id", NEW."created_at", NEW."handled_at", NEW."handled_by_id", NEW."id", NEW."moderator_changes", NEW."notes", NEW."object_id", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."reason", NEW."source", NEW."status", NEW."submission_type", NEW."updated_at", NEW."user_id"); RETURN NULL;',
|
||||
hash="315b76df75a52d610d3d0857fd5821101e551410",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_ab38f",
|
||||
table="moderation_editsubmission",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="photosubmission",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "moderation_photosubmissionevent" ("caption", "content_type_id", "created_at", "date_taken", "handled_at", "handled_by_id", "id", "notes", "object_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "photo", "status", "updated_at", "user_id") VALUES (NEW."caption", NEW."content_type_id", NEW."created_at", NEW."date_taken", NEW."handled_at", NEW."handled_by_id", NEW."id", NEW."notes", NEW."object_id", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."photo", NEW."status", NEW."updated_at", NEW."user_id"); RETURN NULL;',
|
||||
hash="e967ea629575f6b26892db225b40add9a1558cfb",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_62865",
|
||||
table="moderation_photosubmission",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="photosubmission",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "moderation_photosubmissionevent" ("caption", "content_type_id", "created_at", "date_taken", "handled_at", "handled_by_id", "id", "notes", "object_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "photo", "status", "updated_at", "user_id") VALUES (NEW."caption", NEW."content_type_id", NEW."created_at", NEW."date_taken", NEW."handled_at", NEW."handled_by_id", NEW."id", NEW."notes", NEW."object_id", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."photo", NEW."status", NEW."updated_at", NEW."user_id"); RETURN NULL;',
|
||||
hash="b7a97f4e8f90569a90fc4c35cc85e601ff25f0d9",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_9c311",
|
||||
table="moderation_photosubmission",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,89 @@
|
||||
# Generated by Django 5.2.6 on 2025-09-20 13:40
|
||||
|
||||
import pgtrigger.compiler
|
||||
import pgtrigger.migrations
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("parks", "0003_alter_park_id_alter_parkarea_id_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="park",
|
||||
name="insert_insert",
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="park",
|
||||
name="update_update",
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="parkarea",
|
||||
name="insert_insert",
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="parkarea",
|
||||
name="update_update",
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="park",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "parks_parkevent" ("average_rating", "closing_date", "coaster_count", "created_at", "description", "id", "name", "opening_date", "operating_season", "owner_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "ride_count", "size_acres", "slug", "status", "updated_at", "website") VALUES (NEW."average_rating", NEW."closing_date", NEW."coaster_count", NEW."created_at", NEW."description", NEW."id", NEW."name", NEW."opening_date", NEW."operating_season", NEW."owner_id", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."ride_count", NEW."size_acres", NEW."slug", NEW."status", NEW."updated_at", NEW."website"); RETURN NULL;',
|
||||
hash="83eb12a74769e2601a23691085a345c29c9b6f68",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_66883",
|
||||
table="parks_park",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="park",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "parks_parkevent" ("average_rating", "closing_date", "coaster_count", "created_at", "description", "id", "name", "opening_date", "operating_season", "owner_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "ride_count", "size_acres", "slug", "status", "updated_at", "website") VALUES (NEW."average_rating", NEW."closing_date", NEW."coaster_count", NEW."created_at", NEW."description", NEW."id", NEW."name", NEW."opening_date", NEW."operating_season", NEW."owner_id", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."ride_count", NEW."size_acres", NEW."slug", NEW."status", NEW."updated_at", NEW."website"); RETURN NULL;',
|
||||
hash="f42a468ec35a2d51abd5c1ae1afa41b300ae0a1b",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_19f56",
|
||||
table="parks_park",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="parkarea",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "parks_parkareaevent" ("closing_date", "created_at", "description", "id", "name", "opening_date", "park_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "slug", "updated_at") VALUES (NEW."closing_date", NEW."created_at", NEW."description", NEW."id", NEW."name", NEW."opening_date", NEW."park_id", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."slug", NEW."updated_at"); RETURN NULL;',
|
||||
hash="fa64ee07f872bf2214b2c1b638b028429752bac4",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_13457",
|
||||
table="parks_parkarea",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="parkarea",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "parks_parkareaevent" ("closing_date", "created_at", "description", "id", "name", "opening_date", "park_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "slug", "updated_at") VALUES (NEW."closing_date", NEW."created_at", NEW."description", NEW."id", NEW."name", NEW."opening_date", NEW."park_id", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."slug", NEW."updated_at"); RETURN NULL;',
|
||||
hash="59fa84527a4fd0fa51685058b6037fa22163a095",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_6e5aa",
|
||||
table="parks_parkarea",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
12
parks/migrations/0005_auto_20250920_0943.py
Normal file
12
parks/migrations/0005_auto_20250920_0943.py
Normal file
@@ -0,0 +1,12 @@
|
||||
# Generated by Django 5.2.6 on 2025-09-20 13:43
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("parks", "0004_remove_park_insert_insert_remove_park_update_update_and_more"),
|
||||
]
|
||||
|
||||
operations = []
|
||||
17
parks/migrations/0006_auto_20250920_0944.py
Normal file
17
parks/migrations/0006_auto_20250920_0944.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# Generated by Django 5.2.6 on 2025-09-20 13:44
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("parks", "0005_auto_20250920_0943"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunSQL(
|
||||
"ALTER TABLE parks_parkevent ADD COLUMN IF NOT EXISTS owner_id INTEGER;",
|
||||
reverse_sql="ALTER TABLE parks_parkevent DROP COLUMN IF EXISTS owner_id;"
|
||||
),
|
||||
]
|
||||
@@ -57,6 +57,12 @@ class Park(TrackedModel):
|
||||
owner = models.ForeignKey(
|
||||
Company, on_delete=models.SET_NULL, null=True, blank=True, related_name="parks"
|
||||
)
|
||||
operator = models.ForeignKey(
|
||||
Company, on_delete=models.SET_NULL, null=True, blank=True, related_name="operated_parks"
|
||||
)
|
||||
property_owner = models.ForeignKey(
|
||||
Company, on_delete=models.SET_NULL, null=True, blank=True, related_name="owned_properties"
|
||||
)
|
||||
photos = GenericRelation(Photo, related_query_name="park")
|
||||
areas: models.Manager['ParkArea'] # Type hint for reverse relation
|
||||
rides: models.Manager['Ride'] # Type hint for reverse relation from rides app
|
||||
|
||||
@@ -26,6 +26,7 @@ django_settings = "thrillwiki.settings"
|
||||
[project]
|
||||
name = "thrillwiki"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"Django>=5.0",
|
||||
"djangorestframework>=3.14.0",
|
||||
@@ -58,4 +59,5 @@ dependencies = [
|
||||
"pytest-playwright>=0.4.3",
|
||||
"django-pghistory>=3.5.2",
|
||||
"django-htmx-autocomplete>=1.0.5",
|
||||
"python-decouple>=3.8",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# Generated by Django 5.2.6 on 2025-09-20 13:40
|
||||
|
||||
import pgtrigger.compiler
|
||||
import pgtrigger.migrations
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("reviews", "0002_alter_review_id"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="review",
|
||||
name="insert_insert",
|
||||
),
|
||||
pgtrigger.migrations.RemoveTrigger(
|
||||
model_name="review",
|
||||
name="update_update",
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="review",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="insert_insert",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
func='INSERT INTO "reviews_reviewevent" ("content", "content_type_id", "created_at", "id", "is_published", "moderated_at", "moderated_by_id", "moderation_notes", "object_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "rating", "title", "updated_at", "user_id", "visit_date") VALUES (NEW."content", NEW."content_type_id", NEW."created_at", NEW."id", NEW."is_published", NEW."moderated_at", NEW."moderated_by_id", NEW."moderation_notes", NEW."object_id", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."rating", NEW."title", NEW."updated_at", NEW."user_id", NEW."visit_date"); RETURN NULL;',
|
||||
hash="1126891ad95c3c8dc8580ca8b669b6c195960cff",
|
||||
operation="INSERT",
|
||||
pgid="pgtrigger_insert_insert_7a7c1",
|
||||
table="reviews_review",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
pgtrigger.migrations.AddTrigger(
|
||||
model_name="review",
|
||||
trigger=pgtrigger.compiler.Trigger(
|
||||
name="update_update",
|
||||
sql=pgtrigger.compiler.UpsertTriggerSql(
|
||||
condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
|
||||
func='INSERT INTO "reviews_reviewevent" ("content", "content_type_id", "created_at", "id", "is_published", "moderated_at", "moderated_by_id", "moderation_notes", "object_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "rating", "title", "updated_at", "user_id", "visit_date") VALUES (NEW."content", NEW."content_type_id", NEW."created_at", NEW."id", NEW."is_published", NEW."moderated_at", NEW."moderated_by_id", NEW."moderation_notes", NEW."object_id", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."rating", NEW."title", NEW."updated_at", NEW."user_id", NEW."visit_date"); RETURN NULL;',
|
||||
hash="091fc5e3597eddb31fed505798d29859fe8efbe0",
|
||||
operation="UPDATE",
|
||||
pgid="pgtrigger_update_update_b34c8",
|
||||
table="reviews_review",
|
||||
when="AFTER",
|
||||
),
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,21 @@
|
||||
# Generated by Django 5.2.6 on 2025-09-20 13:40
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("rides", "0006_alter_rideevent_options_alter_ridemodelevent_options_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelTable(
|
||||
name="rideevent",
|
||||
table="rides_rideevent",
|
||||
),
|
||||
migrations.AlterModelTable(
|
||||
name="ridemodelevent",
|
||||
table="rides_ridemodelevent",
|
||||
),
|
||||
]
|
||||
310
thrillwiki-nextjs-development-prompt.md
Normal file
310
thrillwiki-nextjs-development-prompt.md
Normal file
@@ -0,0 +1,310 @@
|
||||
# ThrillWiki Next.js Development Prompt
|
||||
|
||||
## Project Overview
|
||||
Build a comprehensive theme park and ride database platform using Next.js. ThrillWiki is a community-driven platform where enthusiasts can discover parks, explore rides, share reviews, and contribute to a moderated knowledge base about theme parks worldwide.
|
||||
|
||||
## Core Application Domain
|
||||
|
||||
### Primary Entities
|
||||
- **Parks**: Theme parks, amusement parks, water parks with detailed information, locations, operating details
|
||||
- **Rides**: Individual ride installations with technical specifications, manufacturer details, operational status
|
||||
- **Companies**: Manufacturers, operators, designers, property owners with different roles
|
||||
- **Users**: Community members with profiles, preferences, reviews, and top lists
|
||||
- **Reviews**: User-generated content with ratings, media, and moderation workflow
|
||||
- **Locations**: Geographic data for parks and rides with PostGIS-style coordinate handling
|
||||
|
||||
### Key Relationships
|
||||
- Parks contain multiple rides and are operated by companies
|
||||
- Rides belong to parks, have manufacturers/designers, and reference ride models
|
||||
- Ride models are templates created by manufacturers with technical specifications
|
||||
- Users create reviews for parks and rides, maintain top lists, have notification preferences
|
||||
- Companies have multiple roles (manufacturer, operator, designer, property owner)
|
||||
- All content goes through moderation workflows before publication
|
||||
|
||||
## User Personas & Workflows
|
||||
|
||||
### Theme Park Enthusiasts
|
||||
- Browse and discover parks by location, type, and features
|
||||
- Search for specific rides and view detailed technical specifications
|
||||
- Plan park visits with operating information and ride availability
|
||||
- Track personal ride credits and maintain top lists
|
||||
- Read authentic reviews from other enthusiasts
|
||||
|
||||
### Content Contributors
|
||||
- Submit new park and ride information for moderation
|
||||
- Upload photos with proper attribution and categorization
|
||||
- Write detailed reviews with ratings and media attachments
|
||||
- Maintain personal profiles with ride statistics and achievements
|
||||
- Participate in community discussions and rankings
|
||||
|
||||
### Park Industry Professionals
|
||||
- Maintain verified company profiles with official information
|
||||
- Update park operating details, ride status, and announcements
|
||||
- Access analytics and engagement metrics for their properties
|
||||
- Manage official media and promotional content
|
||||
|
||||
## Core Features to Implement
|
||||
|
||||
### 1. Park Discovery & Information System
|
||||
- **Park Listings**: Filterable grid/list views with search, location-based filtering, park type categories
|
||||
- **Park Detail Pages**: Comprehensive information including rides list, operating hours, location maps, photo galleries
|
||||
- **Interactive Maps**: Geographic visualization of parks with clustering, zoom controls, and location-based search
|
||||
- **Advanced Search**: Multi-criteria search across parks, rides, locations, and companies
|
||||
|
||||
### 2. Ride Database & Technical Specifications
|
||||
- **Ride Catalog**: Comprehensive database with manufacturer information, technical specs, operational history
|
||||
- **Ride Detail Pages**: In-depth information including statistics, photos, reviews, and related rides
|
||||
- **Manufacturer Profiles**: Company information with ride model catalogs and installation history
|
||||
- **Technical Comparisons**: Side-by-side ride comparisons with filterable specifications
|
||||
|
||||
### 3. User-Generated Content System
|
||||
- **Review Platform**: Structured review forms with ratings, text, photo uploads, and helpful voting
|
||||
- **Photo Management**: Upload system with automatic optimization, categorization, and attribution tracking
|
||||
- **Top Lists**: Personal ranking systems for rides, parks, and experiences with drag-and-drop reordering
|
||||
- **User Profiles**: Personal statistics, ride credits, achievement tracking, and social features
|
||||
|
||||
### 4. Content Moderation Workflow
|
||||
- **Submission Queue**: Administrative interface for reviewing user-submitted content
|
||||
- **Approval Process**: Multi-stage review with rejection reasons, feedback, and resubmission options
|
||||
- **Quality Control**: Automated checks for duplicate content, inappropriate material, and data validation
|
||||
- **User Management**: Moderation tools for user accounts, banning, and content removal
|
||||
|
||||
### 5. Location & Geographic Services
|
||||
- **Location Search**: Address-based search with autocomplete and geographic boundaries
|
||||
- **Proximity Features**: Find nearby parks, distance calculations, and regional groupings
|
||||
- **Map Integration**: Interactive maps with custom markers, clustering, and detailed overlays
|
||||
- **Geographic Filtering**: Location-based content filtering and discovery
|
||||
|
||||
## Technical Architecture Requirements
|
||||
|
||||
### Frontend Stack
|
||||
- **Next.js 14+** with App Router for modern React development
|
||||
- **TypeScript** for type safety and better developer experience
|
||||
- **Tailwind CSS** for utility-first styling and responsive design
|
||||
- **Shadcn/ui** for consistent, accessible component library
|
||||
- **React Hook Form** with Zod validation for form handling
|
||||
- **TanStack Query** for server state management and caching
|
||||
- **Zustand** for client-side state management
|
||||
- **Next-Auth** for authentication and session management
|
||||
|
||||
### Data Management
|
||||
- **API Integration**: RESTful API consumption with comprehensive error handling
|
||||
- **Image Optimization**: Cloudflare Images integration with multiple variants
|
||||
- **Caching Strategy**: Multi-level caching with SWR patterns and cache invalidation
|
||||
- **Search Implementation**: Client-side and server-side search with debouncing
|
||||
- **Infinite Scrolling**: Performance-optimized pagination for large datasets
|
||||
|
||||
### UI/UX Patterns
|
||||
- **Responsive Design**: Mobile-first approach with tablet and desktop optimizations
|
||||
- **Dark/Light Themes**: User preference-based theming with system detection
|
||||
- **Loading States**: Skeleton screens, progressive loading, and optimistic updates
|
||||
- **Error Boundaries**: Graceful error handling with user-friendly messages
|
||||
- **Accessibility**: WCAG compliance with keyboard navigation and screen reader support
|
||||
|
||||
## Key Components to Build
|
||||
|
||||
### Layout & Navigation
|
||||
- **Header Component**: Logo, navigation menu, user authentication, search bar, theme toggle
|
||||
- **Sidebar Navigation**: Collapsible menu with user context and quick actions
|
||||
- **Footer Component**: Links, social media, legal information, and site statistics
|
||||
- **Breadcrumb Navigation**: Contextual navigation with proper hierarchy
|
||||
|
||||
### Park Components
|
||||
- **ParkCard**: Compact park information with image, basic details, and quick actions
|
||||
- **ParkGrid**: Responsive grid layout with filtering and sorting options
|
||||
- **ParkDetail**: Comprehensive park information with tabbed sections
|
||||
- **ParkMap**: Interactive map showing park location and nearby attractions
|
||||
- **OperatingHours**: Dynamic display of park hours with seasonal variations
|
||||
|
||||
### Ride Components
|
||||
- **RideCard**: Ride preview with key specifications and ratings
|
||||
- **RideList**: Filterable list with sorting and search capabilities
|
||||
- **RideDetail**: Complete ride information with technical specifications
|
||||
- **RideStats**: Visual representation of ride statistics and comparisons
|
||||
- **RidePhotos**: Photo gallery with lightbox and attribution information
|
||||
|
||||
### User Interface Components
|
||||
- **UserProfile**: Personal information, statistics, and preference management
|
||||
- **ReviewForm**: Structured review creation with rating inputs and media upload
|
||||
- **TopListManager**: Drag-and-drop interface for creating and managing rankings
|
||||
- **NotificationCenter**: Real-time notifications with read/unread states
|
||||
- **SearchInterface**: Advanced search with filters, suggestions, and recent searches
|
||||
|
||||
### Content Management
|
||||
- **SubmissionForm**: Content submission interface with validation and preview
|
||||
- **ModerationQueue**: Administrative interface for content review and approval
|
||||
- **PhotoUpload**: Drag-and-drop photo upload with progress tracking and optimization
|
||||
- **ContentEditor**: Rich text editor for descriptions and review content
|
||||
|
||||
## Data Models & API Integration
|
||||
|
||||
### API Endpoints Structure
|
||||
```typescript
|
||||
// Parks API
|
||||
GET /api/parks/ - List parks with filtering and pagination
|
||||
GET /api/parks/{slug}/ - Park details with rides and reviews
|
||||
GET /api/parks/{slug}/rides/ - Rides at specific park
|
||||
GET /api/parks/search/ - Advanced park search
|
||||
|
||||
// Rides API
|
||||
GET /api/rides/ - List rides with filtering
|
||||
GET /api/rides/{park_slug}/{ride_slug}/ - Ride details
|
||||
GET /api/rides/manufacturers/{slug}/ - Manufacturer information
|
||||
GET /api/rides/search/ - Advanced ride search
|
||||
|
||||
// User API
|
||||
GET /api/users/profile/ - Current user profile
|
||||
PUT /api/users/profile/ - Update user profile
|
||||
GET /api/users/{username}/ - Public user profile
|
||||
POST /api/users/reviews/ - Create review
|
||||
|
||||
// Content API
|
||||
POST /api/submissions/ - Submit new content
|
||||
GET /api/submissions/status/ - Check submission status
|
||||
POST /api/photos/upload/ - Upload photos
|
||||
GET /api/moderation/queue/ - Moderation queue (admin)
|
||||
```
|
||||
|
||||
### TypeScript Interfaces
|
||||
```typescript
|
||||
interface Park {
|
||||
id: number;
|
||||
name: string;
|
||||
slug: string;
|
||||
description: string;
|
||||
status: string;
|
||||
park_type: string;
|
||||
location: ParkLocation;
|
||||
operator: Company;
|
||||
opening_date: string;
|
||||
ride_count: number;
|
||||
coaster_count: number;
|
||||
average_rating: number;
|
||||
banner_image: Photo;
|
||||
card_image: Photo;
|
||||
url: string;
|
||||
}
|
||||
|
||||
interface Ride {
|
||||
id: number;
|
||||
name: string;
|
||||
slug: string;
|
||||
description: string;
|
||||
park: Park;
|
||||
category: string;
|
||||
manufacturer: Company;
|
||||
ride_model: RideModel;
|
||||
status: string;
|
||||
opening_date: string;
|
||||
height_requirement: number;
|
||||
average_rating: number;
|
||||
coaster_stats?: RollerCoasterStats;
|
||||
}
|
||||
|
||||
interface User {
|
||||
id: number;
|
||||
username: string;
|
||||
display_name: string;
|
||||
profile: UserProfile;
|
||||
role: string;
|
||||
theme_preference: string;
|
||||
privacy_level: string;
|
||||
}
|
||||
```
|
||||
|
||||
## Authentication & User Management
|
||||
|
||||
### Authentication Flow
|
||||
- **Registration**: Email-based signup with verification workflow
|
||||
- **Login**: Username/email login with remember me option
|
||||
- **Social Auth**: Integration with Google, Facebook, Discord for quick signup
|
||||
- **Password Reset**: Secure password reset with email verification
|
||||
- **Two-Factor Auth**: Optional 2FA with authenticator app support
|
||||
|
||||
### User Roles & Permissions
|
||||
- **Regular Users**: Create reviews, manage profiles, submit content
|
||||
- **Verified Contributors**: Trusted users with expedited content approval
|
||||
- **Moderators**: Content review, user management, community oversight
|
||||
- **Administrators**: Full system access, user role management, system configuration
|
||||
|
||||
### Privacy & Security
|
||||
- **Privacy Controls**: Granular privacy settings for profile visibility and data sharing
|
||||
- **Content Moderation**: Automated and manual content review processes
|
||||
- **Data Protection**: GDPR compliance with data export and deletion options
|
||||
- **Security Features**: Login notifications, session management, suspicious activity detection
|
||||
|
||||
## Performance & Optimization
|
||||
|
||||
### Loading & Caching
|
||||
- **Image Optimization**: Cloudflare Images with responsive variants and lazy loading
|
||||
- **API Caching**: Intelligent caching with stale-while-revalidate patterns
|
||||
- **Static Generation**: Pre-generated pages for popular content with ISR
|
||||
- **Code Splitting**: Route-based and component-based code splitting for optimal loading
|
||||
|
||||
### Search & Filtering
|
||||
- **Client-Side Search**: Fast text search with debouncing and result highlighting
|
||||
- **Server-Side Filtering**: Complex filtering with URL state management
|
||||
- **Infinite Scrolling**: Performance-optimized pagination for large datasets
|
||||
- **Search Analytics**: Track popular searches and optimize content discovery
|
||||
|
||||
### Mobile Optimization
|
||||
- **Responsive Design**: Mobile-first approach with touch-friendly interfaces
|
||||
- **Progressive Web App**: PWA features with offline capability and push notifications
|
||||
- **Performance Budgets**: Strict performance monitoring with Core Web Vitals tracking
|
||||
- **Accessibility**: Full keyboard navigation and screen reader compatibility
|
||||
|
||||
## Content Management & Moderation
|
||||
|
||||
### Submission Workflow
|
||||
- **Content Forms**: Structured forms for parks, rides, and reviews with validation
|
||||
- **Draft System**: Save and resume content creation with auto-save functionality
|
||||
- **Preview Mode**: Real-time preview of content before submission
|
||||
- **Submission Tracking**: Status updates and feedback throughout review process
|
||||
|
||||
### Moderation Interface
|
||||
- **Review Queue**: Prioritized queue with filtering and batch operations
|
||||
- **Approval Workflow**: Multi-stage review with detailed feedback options
|
||||
- **Quality Metrics**: Track approval rates, review times, and content quality
|
||||
- **User Reputation**: Contributor scoring system based on submission quality
|
||||
|
||||
### Media Management
|
||||
- **Photo Upload**: Drag-and-drop interface with progress tracking and error handling
|
||||
- **Image Processing**: Automatic optimization, resizing, and format conversion
|
||||
- **Attribution Tracking**: Photographer credits and copyright information
|
||||
- **Bulk Operations**: Batch photo management and organization tools
|
||||
|
||||
## Analytics & Insights
|
||||
|
||||
### User Analytics
|
||||
- **Engagement Tracking**: Page views, time on site, and user journey analysis
|
||||
- **Content Performance**: Popular parks, rides, and reviews with engagement metrics
|
||||
- **Search Analytics**: Popular search terms and content discovery patterns
|
||||
- **User Behavior**: Registration funnels, retention rates, and feature adoption
|
||||
|
||||
### Content Insights
|
||||
- **Submission Metrics**: Content creation rates, approval times, and quality scores
|
||||
- **Review Analytics**: Rating distributions, helpful votes, and review engagement
|
||||
- **Geographic Data**: Popular regions, park visit patterns, and location-based insights
|
||||
- **Trending Content**: Real-time trending parks, rides, and discussions
|
||||
|
||||
## Development Guidelines
|
||||
|
||||
### Code Organization
|
||||
- **Feature-Based Structure**: Organize code by features rather than file types
|
||||
- **Component Library**: Reusable components with Storybook documentation
|
||||
- **Custom Hooks**: Shared logic extraction with proper TypeScript typing
|
||||
- **Utility Functions**: Common operations with comprehensive testing
|
||||
|
||||
### Testing Strategy
|
||||
- **Unit Testing**: Component and utility function testing with Jest and React Testing Library
|
||||
- **Integration Testing**: API integration and user workflow testing
|
||||
- **E2E Testing**: Critical user journeys with Playwright or Cypress
|
||||
- **Performance Testing**: Core Web Vitals monitoring and performance regression testing
|
||||
|
||||
### Deployment & DevOps
|
||||
- **Environment Management**: Development, staging, and production environments
|
||||
- **CI/CD Pipeline**: Automated testing, building, and deployment
|
||||
- **Monitoring**: Error tracking, performance monitoring, and user analytics
|
||||
- **Security**: Regular security audits, dependency updates, and vulnerability scanning
|
||||
|
||||
This comprehensive platform should provide theme park enthusiasts with a rich, engaging experience while maintaining high content quality through effective moderation and community management systems.
|
||||
@@ -11,6 +11,6 @@ import os
|
||||
|
||||
from django.core.asgi import get_asgi_application
|
||||
|
||||
os***REMOVED***iron.setdefault("DJANGO_SETTINGS_MODULE", "thrillwiki.settings")
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "thrillwiki.settings")
|
||||
|
||||
application = get_asgi_application()
|
||||
|
||||
@@ -180,7 +180,7 @@ SOCIALACCOUNT_PROVIDERS = {
|
||||
"google": {
|
||||
"APP": {
|
||||
"client_id": "135166769591-nopcgmo0fkqfqfs9qe783a137mtmcrt2.apps.googleusercontent.com",
|
||||
"[SECRET-REMOVED]",
|
||||
"secret": "[SECRET-REMOVED]",
|
||||
"key": "",
|
||||
},
|
||||
"SCOPE": [
|
||||
@@ -192,7 +192,7 @@ SOCIALACCOUNT_PROVIDERS = {
|
||||
"discord": {
|
||||
"APP": {
|
||||
"client_id": "1299112802274902047",
|
||||
"[SECRET-REMOVED]",
|
||||
"secret": "[SECRET-REMOVED]",
|
||||
"key": "",
|
||||
},
|
||||
"SCOPE": ["identify", "email"],
|
||||
|
||||
@@ -55,7 +55,7 @@ urlpatterns = [
|
||||
path("history/", include("history.urls", namespace="history")),
|
||||
path(
|
||||
"env-settings/",
|
||||
views***REMOVED***ironment_and_settings_view,
|
||||
views.environment_and_settings_view,
|
||||
name="environment_and_settings",
|
||||
),
|
||||
]
|
||||
|
||||
@@ -127,7 +127,7 @@ class SearchView(TemplateView):
|
||||
|
||||
def environment_and_settings_view(request):
|
||||
# Get all environment variables
|
||||
env_vars = dict(os***REMOVED***iron)
|
||||
env_vars = dict(os.environ)
|
||||
|
||||
# Get all Django settings as a dictionary
|
||||
settings_vars = {setting: getattr(settings, setting) for setting in dir(settings) if setting.isupper()}
|
||||
|
||||
@@ -11,6 +11,6 @@ import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os***REMOVED***iron.setdefault("DJANGO_SETTINGS_MODULE", "thrillwiki.settings")
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "thrillwiki.settings")
|
||||
|
||||
application = get_wsgi_application()
|
||||
|
||||
Reference in New Issue
Block a user