Skip to content

ozayn/planner

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

630 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Event Planner App

A minimal, artistic web and mobile app for discovering events in cities worldwide.

🚨 IMPORTANT REMINDERS

🎨 Design Principles & UI Preferences

  • ❌ NO DARK BUTTONS: Avoid using dark background colors for buttons (especially in the admin panel).
  • βœ… Light/Pastel Theme: Prefer light, translucent (rgba), or pastel background colors with dark text.
  • Minimalist Style: Maintain an airy, modern, and minimalist aesthetic.
  • Hover Transitions: Most buttons should be light by default and only become fully saturated on hover.

πŸ”‘ Critical Setup Steps

  • ⚠️ ALWAYS activate virtual environment first: source venv/bin/activate && python
  • ❌ NEVER use python3 directly: Causes "no module named bs4" and other dependency errors
  • βœ… CORRECT: source venv/bin/activate && python scripts/venue_event_scraper.py
  • ❌ WRONG: python3 scripts/venue_event_scraper.py (uses system Python without dependencies)
  • Use port 5001, never 5000: App runs on http://localhost:5001
  • Environment variables: Add API keys to .env file (never commit this file)

πŸ“‹ Maintainer Commands (Data Sync)

Local source reload

curl -X POST http://localhost:5001/api/admin/reload-sources
  • Use after editing data/sources.json
  • Reloads sources from JSON into the local database
  • Verify source changes locally before deploy/sync

Production sync (cities, venues, sources)

# Set PRODUCTION_DATABASE_URL in .env (PostgreSQL public URL from Railway), then:
# Dry run (preview only)
./venv/bin/python scripts/sync_json_to_production.py

# Apply changes
./venv/bin/python scripts/sync_json_to_production.py --apply
  • Syncs cities, venues, and sources only (not events)
  • Run dry run first before --apply
  • Prefer PRODUCTION_DATABASE_URL in .env so you do not need to prefix the command; falls back to DATABASE_URL if it is PostgreSQL
  • Use Railway Postgres public URL when running from a laptop (do not use postgres.railway.internal locally)
  • Duplicate conflicts are skipped for manual review

πŸ€– Hybrid OCR + LLM System

  • Default OCR: Tesseract (local), Google Vision API (deployment)
  • LLM Processing: Google Gemini for intelligent event extraction
  • Smart Detection: Automatically chooses optimal OCR engine
  • Instagram Context: Extracts page names, handles, and poster info
  • Intelligent Processing: 90% confidence with Vision API, 80% with Tesseract

πŸ”— Create Events from URL (βœ… FIXED)

STATUS: Feature fully functional - Auto-Fill button now works correctly!

What Works:

  • πŸ“‹ Paste Any Event URL: Automatically scrape and create events from web pages
  • πŸ” Auto-Fill Button: Click to extract event details before creating
  • πŸ“… Smart Time Periods: Choose today, tomorrow, this week, this month, or custom dates
  • πŸ”„ Recurring Event Handling: Detects schedules like "Fridays 6:30pm - 7:30pm" or "Weekdays 3pm"
  • πŸ“Š Multi-Event Creation: Automatically creates events for all matching days in period
  • 🎯 Intelligent Extraction: Pulls title, description, times, and images from page
  • πŸ›‘οΈ Bot Protection Bypass: Uses cloudscraper with retry logic (Railway-compatible)
  • πŸ€– LLM Fallback: Automatically uses AI (Gemini/Groq) when web scraping is blocked
  • βœ… Duplicate Prevention: Skips events that already exist in database

βœ… Recently Fixed Issues:

  1. Auto-Fill Button Fixed (October 10, 2025):

    • Problem: Button click with onclick="autoFillFromUrl(event)" wasn't triggering
    • Root Cause: Event parameter not properly passed in inline onclick handler
    • Solution:
      • Removed inline onclick handler
      • Added button ID (autoFillBtn)
      • Simplified autoFillFromUrl() to not require parameters
      • Added proper event listener in openUrlScraperModal()
    • Status: βœ… Fully functional
  2. Venue Dropdown Loading:

    • Fixed: Changed from /api/venues to /api/admin/venues
    • Status: βœ… Working
  3. LLM Fallback Added (October 10, 2025):

    • Enhancement: Added automatic LLM extraction when bot protection blocks scraping
    • How it Works: Tries web scraping first (3 attempts), then automatically uses LLM
    • LLM Providers: Google Gemini, Groq, OpenAI, Anthropic (automatic fallback chain)
    • Result: Bot-protected sites (like Met Museum) now work!
    • Indicator: Extracted data includes llm_extracted: true and confidence level
    • Status: βœ… Fully functional

How to Use:

  1. Click "πŸ”— From URL" button in Events section
  2. Paste event page URL
  3. Click "πŸ” Auto-Fill" button (now works!)
  4. Review and edit extracted data
  5. Select venue (optional) and city (required)
  6. Choose time period for recurring events
  7. Click "πŸ”— Create Events"

Backend Status:

  • βœ… /api/admin/extract-event-from-url endpoint functional
  • βœ… extract_event_data_from_url() function works
  • βœ… Cloudscraper bypasses bot protection
  • βœ… Schedule detection works ("Fridays 6:30pm - 7:30pm")
  • βœ… /api/admin/scrape-event-from-url creates events correctly

Frontend Status:

  • βœ… Auto-Fill button click handler (FIXED)
  • βœ… Event parameter passing (FIXED)
  • βœ… Preview section display
  • βœ… Form submission with extracted data

Testing:

# Test extraction API
curl -X POST http://localhost:5001/api/admin/extract-event-from-url \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'

πŸ“– For detailed usage guide, see docs/URL_EVENT_CREATION_GUIDE.md

🎯 Event Scraping Intelligence

  • Today-Focused: Scrapes events for TODAY only (more relevant and useful)
  • Smart Schedule Detection:
    • Reads actual webpage content to find schedule (e.g., "Fridays 6:30pm - 7:30pm")
    • Day-aware filtering: Only shows events if today matches the specified day
    • Uses cloudscraper to bypass bot protection (Railway-compatible, no browser needed)
    • Extracts both start AND end times from page text
    • Falls back to URL-based time extraction (e.g., "630pm" in URL β†’ 6:30 PM)
  • Tour Duration Assumption: If no end time is specified, assumes 1-hour duration
    • Example: 3:00 PM start β†’ 4:00 PM end (automatically calculated)
    • Essential for Google Calendar integration - calendar events require both start and end times
    • Makes events more complete and useful for planning
  • Enhanced Title Extraction: Converts generic dates to descriptive titles
    • "Friday, October 10" β†’ "Museum Highlights Tour"
    • "Collection Tour: Islamic Art" (from actual page titles)
  • Meeting Point Detection: Extracts specific locations like "Gallery 534, VΓ©lez Blanco Patio"

🌐 Generic Venue Scraper (Universal Fallback)

  • 🚨 CRITICAL RULE: Unless we have made a tailored scraper, the generic scraper should be used
    • Any venue without a specialized/tailored scraper MUST use the generic scraper
    • The generic scraper is the default for all venues
    • Only venues with explicitly implemented tailored scrapers should bypass the generic scraper
  • Universal Compatibility: A generic scraper (scripts/generic_venue_scraper.py) that works for any venue/location by using common patterns learned from specialized scrapers
  • Two-Tier Architecture:
    • Specialized Scrapers (Priority): Custom scrapers for specific venues (Hirshhorn, NGA, etc.) with venue-specific logic
    • Generic Scraper (Default): Universal scraper that uses common HTML patterns, CSS selectors, and extraction methods - used for ALL venues unless a tailored scraper exists
  • Automatic Usage: The system automatically uses the generic scraper for any venue that doesn't have a tailored scraper implementation
  • Pattern-Based Extraction: Uses patterns learned from specialized scrapers:
    • Common CSS selectors (.event, .event-item, .program, .tour, etc.)
    • JSON-LD structured data extraction
    • Multiple date/time format parsing
    • Automatic event type detection
    • Image extraction from listing pages
  • Continuous Improvement: The generic scraper is designed to evolve - as we create new specialized scrapers or discover new patterns, we extract reusable patterns and add them to the generic scraper, making it work better for more venues over time
  • Error Handling: Includes bot protection bypass (cloudscraper), SSL error handling, and retry logic
  • Documentation: See docs/GENERIC_SCRAPER_GUIDE.md for detailed usage and integration examples

πŸ”„ Scraping Workflow & Architecture Goals

  • Development Phase (Current): Individual scraper buttons in admin interface for testing specific venues/museums

    • Used for development and debugging individual scrapers
    • Each scraper (NGA, SAAM, Asian Art, etc.) has its own button for quick testing
    • Note: These are temporary development tools, not the final production workflow
  • Production Phase (Manual): Unified scraping interface via main page

    • Workflow: Main page β†’ Select city β†’ Select filters (venues/sources) β†’ Click "Scrape" button
    • The unified scraping system (/api/scrape) handles all selected venues/sources automatically
    • Uses progress tracking with real-time updates in the UI
    • Supports filtering by city, event type, time range, and specific venues/sources
  • Production Phase (Automated): Cronjob-based scheduled scraping

    • Scrapers will run automatically on a schedule (e.g., daily, hourly)
    • All scrapers must be callable programmatically (not just from UI)
    • Comprehensive logging for monitoring and debugging
    • Error handling that works without UI dependencies
    • Progress tracking is optional for cronjobs (no UI needed)
  • Standard Pattern for All Scrapers:

    • Backend: Progress tracking via scraping_progress.json, error handling, always return JSON
    • Frontend: Progress modal with real-time updates, table refreshes during scraping
    • Database Saving: Update progress every 5 events for real-time feedback
    • Error Handling: Graceful degradation - continue with other events if one fails
    • Timeout Handling: Retry logic with exponential backoff, increased timeout values
    • Standalone Operation: All scrapers work both from UI and programmatically (for cronjobs)

🌐 Deployment Configuration

  • Platform: Railway with custom domain planner.ozayn.com
  • Database: PostgreSQL (Railway managed)
  • Environment Detection: Automatically switches OCR engines based on environment
  • Security: All API keys properly protected, no exposed credentials
  • 🚨 DEPLOYMENT PREFERENCE:
    • βœ… ALWAYS use GitHub integration: Push to GitHub and let Railway auto-deploy
    • ❌ NEVER use railway up: Bypasses GitHub, creates inconsistency
    • Deployment process: git push β†’ Railway auto-detects β†’ Builds β†’ Runs reset_railway_database.py β†’ Deploys
    • Wait time: ~2-3 minutes for automatic deployment to complete

πŸ”„ Syncing Data Between Local & Production

  • ⚠️ CRITICAL: Local SQLite and Railway PostgreSQL have different city IDs
    • Local: New York = city_id 2, Washington = city_id 1
    • Production: New York = city_id 452, Washington = city_id 451

βž• Adding New Cities (Complete Workflow)

  • 🚨 IMPORTANT: After adding a city to data/cities.json, you MUST reload it into the database
  • Complete Workflow (follow these exact steps):
    1. Add city to JSON: Edit data/cities.json and add your new city entry
      • Example format:
      "28": {
        "name": "Coimbra",
        "state": "",
        "country": "Portugal",
        "timezone": "Europe/Lisbon"
      }
    2. Reload cities into local database:
      curl -X POST http://localhost:5001/api/admin/reload-cities
      • This updates existing cities and adds new ones from cities.json (preserves city IDs to avoid breaking events/venues/sources)
      • Verify: Check admin interface or curl http://localhost:5001/api/admin/cities
    3. Commit and push JSON file:
      git add data/cities.json
      git commit -m "Add new city: [City Name]"
      git push
    4. Wait for Railway deployment (2-3 minutes)
    5. Reload cities in production:
      curl -X POST https://planner.ozayn.com/api/admin/reload-cities
    6. Verify: Check production admin interface or API endpoint
  • Why reload is needed: The JSON file is the source of truth, but cities must be loaded into the database to appear in the app
  • Common mistake: Adding to JSON but forgetting to reload β†’ city won't appear in admin interface or dropdowns
  • βœ… Safe to reload: The reload process preserves existing cities (updates them instead of deleting), so your events, venues, and sources remain linked correctly

πŸ”„ Syncing Production Changes Back to JSON (Reverse Workflow)

  • When to use: If you add/edit a city, venue, or source directly in production (via admin interface)
  • Problem: Changes are in production database but NOT in JSON files β†’ will be lost on next reload
  • Solution: Update JSON files from production database, then commit to git

Complete Workflow (follow these exact steps):

  1. Update JSON files from production database:

    # Update all JSON files at once (recommended)
    curl -X POST https://planner.ozayn.com/api/admin/update-all-json
    
    # Or update individually:
    curl -X POST https://planner.ozayn.com/api/admin/update-cities-json
    curl -X POST https://planner.ozayn.com/api/admin/update-venues-json
    curl -X POST https://planner.ozayn.com/api/admin/update-sources-json
    • This updates the JSON files directly in the data/ directory on production
  2. Pull updated JSON files from git (after Railway auto-commits or manual commit):

    git pull origin master
    • Note: On Railway, file changes are ephemeral. You need to either:
      • Option A: Download the updated files and commit manually (see Alternative below)
      • Option B: Use Railway CLI to commit changes (if configured)
  3. Verify JSON files are correct (check structure matches expected format)

  4. Commit and push (if files were downloaded manually):

    git add data/*.json
    git commit -m "Sync JSON files from production database"
    git push
  5. Reload in local (optional, to sync local database):

    curl -X POST http://localhost:5001/api/admin/reload-cities
    curl -X POST http://localhost:5001/api/admin/reload-venues-from-json
    curl -X POST http://localhost:5001/api/admin/reload-sources

Alternative: Download and commit manually:

  1. Download updated JSON files from production:

    # After running update-all-json, download the files
    # (You may need to access Railway file system or use export endpoints)
    curl -X POST https://planner.ozayn.com/api/admin/export-cities -o data/cities.json
    curl -X POST https://planner.ozayn.com/api/admin/export-venues -o data/venues.json
    curl -X POST https://planner.ozayn.com/api/admin/export-sources -o data/sources.json
  2. Commit and push:

    git add data/*.json
    git commit -m "Sync JSON files from production database"
    git push

⚠️ Important: Always update JSON files from production and commit them after making changes in production, otherwise changes will be lost on next reload!

πŸ’‘ Best Practice: After adding/editing cities, venues, or sources in production:

  1. Immediately run /api/admin/update-all-json to sync JSON files
  2. Download and commit the updated JSON files to git
  3. This ensures consistency between production database and JSON files
  • Syncing Workflow (follow these exact steps):
    1. Make data changes locally (e.g., update venue URLs in local database)
    2. Export to JSON: source venv/bin/activate && python scripts/update_venues_json.py (or cities, sources)
    3. Commit and push JSON files: git add data/*.json && git commit -m "Update venue data" && git push
    4. Wait 2-3 minutes for Railway auto-deploy
    5. Call reload endpoint: curl -X POST https://planner.ozayn.com/api/admin/reload-venues-from-json
    6. Verify changes: Check production at https://planner.ozayn.com/api/admin/venues
  • Available Reload Endpoints:
    • /api/admin/reload-cities - Reload cities from cities.json (updates existing, adds new - preserves IDs)
      • Updates existing cities by name (preserves city IDs to avoid breaking events/venues/sources)
      • Adds new cities that don't exist
      • Returns: {cities_updated, cities_added, cities_skipped, total_cities}
    • /api/admin/reload-venues-from-json - Sync venues from JSON to production DB
      • Matches venues by name only (handles city_id mismatch between environments)
      • Updates existing venues (preserves venue IDs)
      • Adds new venues that don't exist
      • Updates all venue fields (website_url, social media, contact info, etc.)
      • Returns stats: {updated_count, venues_in_json, venues_matched}
    • /api/admin/reload-sources - Reload sources from sources.json (updates existing, adds new - preserves IDs)
      • Updates existing sources by name (preserves source IDs)
      • Adds new sources that don't exist
      • Returns: {sources_updated, sources_added, sources_skipped, total_sources}
    • /api/admin/load-all-data - Load all data (cities, venues, sources) from JSON files
      • Use this after deployment if venues/sources are empty
      • Updates existing items and adds new ones (preserves IDs - safe for existing events)
      • Handles city matching automatically (case-insensitive)
      • Returns: {cities_loaded, venues_loaded, venues_skipped, sources_loaded, total_items}
  • Available Update Endpoints (for syncing production β†’ JSON):
    • /api/admin/update-cities-json - Update data/cities.json from production database
    • /api/admin/update-venues-json - Update data/venues.json from production database
    • /api/admin/update-sources-json - Update data/sources.json from production database
    • /api/admin/update-all-json - Update all JSON files at once (recommended)
    • Use these when you add/edit cities/venues/sources in production and need to sync back to JSON files
  • Why Not railway run?:
    • ❌ Can't run local scripts on Railway (connection to postgres.railway.internal fails)
    • βœ… Use API endpoints instead - they run in production environment with access to production DB
  • Data Flow: Local DB β†’ JSON files β†’ Git β†’ Railway β†’ Reload API β†’ Production DB
  • Common Issue: If URLs don't update, check that JSON was committed/pushed and Railway finished deploying
  • Fix Script Available: Use scripts/fix_all_venue_urls.py to fix known fake URLs in batch
  • 🚨 After Railway Deployment: If venues/sources are empty, call /api/admin/load-all-data to reload everything
  • Venue Loading Structure:
    • venues.json has venues at top level (not nested under cities)
    • Each venue has a city_name field used for matching
    • City matching is case-insensitive and handles different formats
    • If venues don't load, check venues_skipped count in response
  • Venue Loading Notes:
    • venues.json structure: Venues are at top level, each has city_name field
    • City matching is case-insensitive and handles different formats
    • If venues_skipped > 0, check Railway logs for city matching errors
    • The endpoint loads cities first, then venues (matching by city_name), then sources
  • 🚨 After Railway Deployment: If venues/sources are empty, call /api/admin/load-all-data to reload everything

πŸ› Troubleshooting Common Issues

  • "no module named bs4" Error:
    • Cause: Using system Python instead of virtual environment
    • Solution: source venv/bin/activate && python instead of python3
    • Check: which python should show /Users/oz/Dropbox/2025/planner/venv/bin/python
  • "no module named requests" Error:
    • Cause: Same issue - virtual environment not activated
    • Solution: Always use source venv/bin/activate && python
  • Port 5000 already in use:
    • Cause: Another app using port 5000
    • Solution: Use port 5001 (already configured in app.py)
  • Railway deployment fails:
    • Cause: Missing dependencies or environment variables
    • Solution: Check requirements.txt and .env file are committed
  • Venues/Sources Empty After Deployment:
    • Cause: Railway deployment may clear database or fail to reload data
    • Solution: Call reload endpoint after deployment: curl -X POST https://planner.ozayn.com/api/admin/load-all-data
    • Note: The /api/admin/load-all-data endpoint updates/adds cities, venues, and sources from JSON files (preserves existing IDs)
    • Structure: venues.json has venues at top level with city_name field (not nested under cities)
    • City Matching: Uses case-insensitive matching to find cities by name
    • Response: Check venues_loaded and venues_skipped in response to debug issues
    • Known Issue (Fixed): The load-all-data endpoint had a bug where it returned early after loading venues, preventing sources from loading. This has been fixed.
    • If venues still don't load: Check Railway logs for city matching errors - venues are skipped if their city_name doesn't match any city in the database
    • βœ… Safe to use: The endpoint now updates/adds instead of deleting, so existing events remain linked

⚠️ JavaScript Variable Scope - Admin Table Sorting

CRITICAL LESSON LEARNED: Never declare local variables that shadow window-scoped data arrays!

The Bug Pattern (DO NOT DO THIS):

// ❌ WRONG - Creates local variable that shadows window scope
let allSources = [];

async function loadSources() {
    allSources = await fetch('/api/admin/sources').then(r => r.json());
    // Problem: sortTable() looks for window.allSources but finds local allSources
}

function sortTable(tableId, field) {
    dataArray = window.allSources;  // ❌ Undefined! Local variable shadows it
}

The Correct Pattern (DO THIS):

// βœ… CORRECT - No local declaration, uses window scope directly

async function loadSources() {
    window.allSources = await fetch('/api/admin/sources').then(r => r.json());
    // Now sortTable() can find window.allSources correctly
}

function sortTable(tableId, field) {
    dataArray = window.allSources;  // βœ… Works! Finds window-scoped variable
}

Why This Matters:

  • Admin table sorting relies on window.allEvents, window.allVenues, window.allCities, window.allSources
  • Local variable declarations (let, const, var) create shadowing in that scope
  • Symptom: Sorting appears broken, console shows "Data arrays not available"
  • Fix: Remove local declarations, always use window.variableName explicitly

Checklist for New Admin Tables:

  • ❌ NO let allTableName = [] declarations
  • βœ… USE window.allTableName in load function
  • βœ… USE window.allTableName in all references
  • βœ… USE window.filteredTableName for filtered data
  • βœ… TEST sorting immediately after adding new table

Real Example - Sources Table Bug:

// Before (BROKEN):
let allSources = [];  // ❌ This line broke sorting!
async function loadSources() {
    allSources = await response.json();  // Sets local, not window
}

// After (FIXED):
// No declaration here!
async function loadSources() {
    window.allSources = await response.json();  // βœ… Sets window scope
}

Remember: Events, Venues, and Cities tables work because they DON'T have local declarations!

πŸ”’ Security & API Keys

  • NEVER commit .env file: Contains sensitive API keys and secrets
  • NEVER hardcode API keys: Always use environment variables
  • Check .gitignore: Ensure .env, *.key, *.pem files are ignored
  • Rotate keys regularly: Change API keys periodically for security
  • Use different keys: Separate keys for development, staging, and production
  • Monitor key usage: Check API dashboards for unusual activity
  • Secure credentials file: config/google-vision-credentials.json contains Google service account
  • Environment-specific configs: Use FLASK_ENV=development locally, production on Railway
  • Security tools available:
    • Run ./scripts/security_check.sh to scan for exposed secrets
    • Use ./clean_api_key.sh if API keys were accidentally committed

πŸ’» Development Rules

  • Always use modal forms for edit functions: Never use prompt() dialogs for editing data
  • Prevent event bubbling: Add event.stopPropagation() to action buttons to prevent row click events
  • Use proper form validation: All modals should have client-side and server-side validation
  • Maintain consistent UX: All tables should follow the same interaction patterns
  • 🚨 Database schema changes: When adding/modifying table columns, update ALL related components:
    • Model definition: Add new fields to SQLAlchemy model class
    • Database migration: βœ… AUTOMATIC - Schema auto-migrates on Railway startup
    • Modal forms: Add/edit forms must include new fields with proper validation
    • Table headers: Update display logic to show new fields
    • API endpoints: Update all CRUD endpoints to handle new fields
    • Data processing: Update hybrid event processor and extraction logic
    • Form validation: Add client-side and server-side validation for new fields
    • JavaScript functions: Update all functions that reference field names
    • Calendar integration: Update calendar event creation to include new fields
    • Deployment database: βœ… AUTOMATIC - Railway PostgreSQL auto-syncs with local SQLite
    • Backward compatibility: Maintain legacy field support during transition
    • Testing: Test all forms, APIs, and integrations with new schema
    • 🚨 CRITICAL: Monitor ALL processes that populate form fields:
      • LLM prompts: Update extraction prompts to request new fields
      • Response parsing: Update JSON parsing logic to handle new fields
      • Fallback extraction: Update regex patterns and fallback logic
      • Data flow tracing: Follow data from extraction β†’ processing β†’ storage β†’ display
      • Field mapping: Ensure all field references are updated consistently
      • Logging: Update log messages to reflect new field names

πŸ”„ Schema Synchronization (SOLVED)

  • βœ… Automatic Migration: The app now automatically migrates Railway PostgreSQL to match local SQLite schema on startup
  • βœ… No Manual Steps: Schema changes are automatically deployed when you push code to GitHub
  • βœ… Type Conversion: SQLite types are automatically converted to PostgreSQL equivalents
  • βœ… Error Handling: Migration failures are logged but don't crash the app
  • Manual Sync: If needed, run python scripts/sync_schema.py with Railway environment

πŸ“š Lessons Learned from Schema Issues

  • Problem: Railway PostgreSQL doesn't automatically create new columns when SQLAlchemy models are updated
  • Root Cause: SQLAlchemy only creates tables, not column additions, on existing databases
  • Solution: Auto-migration function runs on Railway startup to add missing columns
  • Key Insight: Always define expected columns in code rather than reading from local SQLite (which doesn't exist on Railway)
  • Dashboard Impact: Missing columns cause API errors, resulting in "undefined" counts on admin dashboard
  • Prevention: The auto-migration function prevents this recurring problem permanently

πŸ”§ Troubleshooting Schema Issues

  • Symptom: Dashboard shows "undefined" counts for Cities, Venues, Events, Sources
  • Cause: Missing columns in Railway PostgreSQL database
  • Check: Look for errors like "column events.social_media_platform does not exist" in Railway logs
  • Solution: The auto-migration should fix this automatically on next deployment
  • Manual Fix: If auto-migration fails, run python scripts/sync_schema.py with Railway environment
  • Verification: Check API endpoints return correct counts: /api/admin/cities, /api/admin/venues, etc.
  • 🚨 Timezone handling: Always use CITY timezone for event date/time processing:
    • Image upload event extraction MUST use city timezone, not server timezone
    • Date/time parsing should consider the event's location timezone
    • Never use datetime.now() or date.today() without timezone context

πŸ”§ Testing & Debugging

  • Test in both environments: Always test locally AND on Railway deployment
  • Check browser console: Look for JavaScript errors before reporting issues
  • Verify data persistence: After adding/editing, refresh page to confirm data saved
  • Test all CRUD operations: Create, Read, Update, Delete for each entity type
  • Mobile responsiveness: Test on mobile devices - app uses pastel design for mobile-first
  • 🚨 Always check .env file first: When troubleshooting, check .env for API keys, configuration, and environment settings

πŸ“ File Organization

  • Never modify files in /archive/: These are outdated - use current files in root directories
  • Keep scripts in /scripts/: All utility scripts belong there, not in root
  • Update documentation: When changing functionality, update relevant docs in /docs/
  • Use proper imports: Import from correct modules (e.g., scripts/utils.py, not utils.py)

πŸš€ Performance & Optimization

  • Monitor API calls: Check browser Network tab for failed requests
  • Image optimization: Large images in /uploads/ can slow down the app
  • Database queries: Use browser dev tools to monitor slow database operations
  • Memory leaks: Check for JavaScript memory leaks in long-running sessions

πŸ“Š Current System Status

  • Cities: 25 loaded
  • Venues: 178 loaded
  • Sources: 37 loaded
  • Hybrid Processing: βœ… Production ready
  • Instagram Recognition: βœ… Working perfectly

✨ Features

  • 🌍 Global Cities: Support for 22 major cities worldwide with 147+ venues
  • πŸ›οΈ Venue Management: Comprehensive venue database with images, hours, and details
  • πŸ“° Event Sources: 36+ event sources for Washington DC with smart scraping
  • 🎨 Minimal Design: Pastel colors, artistic fonts, icon-based UI
  • πŸ”§ Admin Interface: Full CRUD operations for cities, venues, and sources
  • πŸ›‘οΈ Bulletproof Setup: Automated restart script with dependency management
  • πŸ€– LLM Integration: Multiple AI providers (Groq, OpenAI, Anthropic, etc.)
  • πŸ“Š Data Management: JSON-based data with database synchronization

πŸš€ Quick Start

⚠️ IMPORTANT: Always activate virtual environment first!

Option 1: Automated Setup

# Clone and setup
git clone https://github.com/ozayn/planner.git
cd planner

# πŸ”₯ ALWAYS RUN THIS FIRST!
source venv/bin/activate

# Create virtual environment (if not exists)
python3 -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install with setup.py (recommended)
python setup.py install

# Or install dependencies manually
pip install -r requirements.txt

# Setup environment
cp .env.example .env
# Edit .env with your API keys

# Initialize database
python scripts/data_manager.py load

# Start the app
python app.py

Option 2: Manual Setup Only

# Clone and setup
git clone https://github.com/ozayn/planner.git
cd planner

# πŸ”₯ ALWAYS RUN THIS FIRST!
source venv/bin/activate

# Create virtual environment (if not exists)
python3 -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install dependencies
pip install -r requirements.txt

# Setup environment
cp .env.example .env
# Edit .env with your API keys

# Initialize database
python scripts/data_manager.py load

# Start the app
python app.py

Visit: http://localhost:5001

πŸ“– For detailed setup instructions, see docs/setup/SETUP_GUIDE.md

🎭 Event Types

🚢 Tours

  • Museum tours with start/end times
  • Meeting locations (entrance, rotunda, specific floors)
  • Images (tour-specific or museum default)
  • Opening hours tracking
  • Google Calendar integration

πŸ›οΈ Venues

  • Museums, buildings, locations
  • Opening hours for specific dates
  • Location and images
  • Instagram links for additional events

🎨 Exhibitions

  • Date ranges
  • Specific locations within venues
  • Multi-day calendar events

πŸŽͺ Festivals

  • Single or multi-day events
  • Multiple locations for different days

πŸ“Έ Photowalks

  • Start/end times and locations
  • Descriptions and details

πŸ› οΈ Technical Stack

  • Backend: Python Flask with SQLAlchemy
  • Database: SQLite (local development), PostgreSQL (Railway production)
  • Frontend: HTML/CSS/JavaScript with minimal design
  • AI Integration: Multiple LLM providers (Groq, OpenAI, Anthropic, Cohere, Google, Mistral)
  • Data Management: JSON files with database synchronization
  • Admin Interface: Dynamic CRUD operations
  • Deployment: Railway-ready with Procfile
  • Design: Pastel colors, minimal UI, icon-based interactions

πŸ“ Project Structure

planner/
β”œβ”€β”€ app.py                 # Main Flask application
β”œβ”€β”€ data/                  # JSON data files
β”‚   β”œβ”€β”€ cities.json        # Predefined cities
β”‚   β”œβ”€β”€ venues.json        # Predefined venues
β”‚   └── sources.json       # Event sources
β”œβ”€β”€ scripts/               # Utility scripts
β”‚   β”œβ”€β”€ data_manager.py    # Database management
β”‚   β”œβ”€β”€ utils.py           # Core utilities
β”‚   β”œβ”€β”€ env_config.py      # Environment configuration
β”‚   └── enhanced_llm_fallback.py # LLM integration
β”œβ”€β”€ templates/             # HTML templates
β”‚   β”œβ”€β”€ index.html         # Main web interface
β”‚   β”œβ”€β”€ admin.html         # Admin interface
β”‚   └── debug.html         # Debug interface
β”œβ”€β”€ docs/                  # πŸ“š Comprehensive Documentation
β”‚   β”œβ”€β”€ setup/             # Setup & installation guides
β”‚   β”œβ”€β”€ deployment/        # Deployment guides
β”‚   β”œβ”€β”€ admin/             # Admin interface docs
β”‚   β”œβ”€β”€ data/              # Data management guides
β”‚   β”œβ”€β”€ session-notes/     # Development session notes
β”‚   └── README.md          # Documentation index
β”œβ”€β”€ archive/               # Archived files
β”‚   β”œβ”€β”€ outdated_scripts/  # Old scripts
β”‚   └── outdated_docs/     # Old documentation
β”œβ”€β”€ requirements.txt       # Production dependencies
β”œβ”€β”€ restart.sh            # Bulletproof restart script
β”œβ”€β”€ setup_github.sh       # GitHub setup script
└── README.md             # This file

πŸ“š Documentation

All documentation is organized in the docs/ directory:

βš™οΈ Configuration

Environment Variables (.env)

# LLM API Keys (optional - app works without them)
GROQ_API_KEY=your_groq_api_key
OPENAI_API_KEY=your_openai_api_key
ANTHROPIC_API_KEY=your_anthropic_api_key
COHERE_API_KEY=your_cohere_api_key
GOOGLE_API_KEY=your_google_api_key
MISTRAL_API_KEY=your_mistral_api_key

# Google Maps (optional)
GOOGLE_MAPS_API_KEY=your_google_maps_api_key

# Eventbrite API (optional - for scraping Eventbrite events)
# Use Personal OAuth Token (Private Token) - this is what you need for reading public events
EVENTBRITE_API_TOKEN=your_eventbrite_personal_oauth_token
# Alternative name (both work):
# EVENTBRITE_PRIVATE_TOKEN=your_eventbrite_personal_oauth_token
# Optional: Public token for anonymous access (limited functionality)
# EVENTBRITE_PUBLIC_TOKEN=ZRQRSTL4V3Y5X2X5X2X5

# Flask Configuration
FLASK_ENV=development
FLASK_DEBUG=True
SECRET_KEY=your_secret_key

# Database
DATABASE_URL=sqlite:///instance/events.db

🎨 Design System

Colors

  • Primary Pastel: #E8F4FD
  • Secondary Pastel: #F0F8E8
  • Accent Pastel: #FFF0F5
  • Neutral Pastel: #F8F9FA

Fonts

  • Display: Playfair Display (artistic serif)
  • Body: Inter (clean sans-serif)

Principles

  • Minimal text, maximum icons
  • Soft shadows and rounded corners
  • No dark buttons or harsh edges
  • Pastel color palette throughout

πŸ“Š Database Schema

The app uses a comprehensive database schema supporting:

  • Cities with timezone information
  • Venues with opening hours
  • Multiple event types (tours, exhibitions, festivals, photowalks, workshops)
  • Polymorphic event inheritance
  • Calendar integration tracking

πŸ”§ API Endpoints

  • GET /api/cities - Get available cities
  • GET /api/events - Get events with filters
  • GET /api/venues - Get venues for a city
  • POST /api/calendar/add - Add event to Google Calendar

🌐 Supported Cities

Currently seeded with 22 cities including:

  • Washington, DC (38 venues, 36 sources)
  • New York, NY (10 venues)
  • Los Angeles, CA (5 venues)
  • San Francisco, CA (5 venues)
  • Chicago, IL (5 venues)
  • Boston, MA (5 venues)
  • Seattle, WA (5 venues)
  • Miami, FL (5 venues)
  • London, UK (10 venues)
  • Paris, France (10 venues)
  • Tokyo, Japan (5 venues)
  • Sydney, Australia (5 venues)
  • Montreal, Canada (5 venues)
  • Toronto, Canada (5 venues)
  • Vancouver, Canada (5 venues)
  • Tehran, Iran (5 venues)
  • Baltimore, MD (5 venues)
  • Philadelphia, PA (5 venues)
  • Madrid, Spain (5 venues)
  • Berlin, Germany (5 venues)
  • Munich, Germany (5 venues)
  • Princeton, NJ (9 venues)

πŸ—οΈ Professional Structure

This project follows professional Python development practices:

  • Clean Architecture: Separated concerns with config/, scripts/, tests/ directories
  • Modular Design: Each component has its own module with proper imports
  • Testing Suite: Comprehensive unit tests in tests/ directory
  • Configuration Management: Environment-based configuration with settings.py
  • Development Tools: Separate requirements-dev.txt for development dependencies
  • Documentation: Comprehensive README and inline documentation
  • Code Organization: No messy files in root directory - everything properly organized

πŸ”§ Troubleshooting

Quick Fixes

  • 🚨 Image processing broken? β†’ QUICK_FIX_GUIDE.md
  • Port 5000 in use: App runs on port 5001 by default
  • Database errors: Run python scripts/data_manager.py load to reload data
  • Python not found: Use python3 instead of python
  • Dependencies not found: Make sure virtual environment is activated with source venv/bin/activate
  • API key errors: Add your API keys to .env file (GROQ_API_KEY, OPENAI_API_KEY, etc.)

Getting Help

🀝 Contributing

  1. Follow the minimal design principles
  2. Use pastel colors and artistic fonts
  3. Prefer icons over text labels
  4. Maintain timezone accuracy
  5. Test on both web and mobile
  6. Follow the established project structure
  7. Add tests for new features
  8. Update documentation as needed

πŸ“„ License

MIT License - feel free to use and modify!

About

Event planning web application with venue discovery and management

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

Β 
Β 
Β 

Contributors