Files
CGW-Quote-Builder/information/PRODUCT_FINDER_DEPLOYMENT.md
T
2026-04-11 00:04:09 -05:00

9.5 KiB

/product-finder Deployment Fix Guide

🔴 Problem

The application works locally at http://localhost:8080/ but fails on the server at https://columbiawindows.com/product-finder/.

The redirect from /product-finder/product-finder/login works, but then the login page or subsequent routes fail.

Solution Applied

Three critical changes were made to fix subdirectory deployment:

1. Added PrefixMiddleware to app.py

This middleware tells Flask about the /product-finder prefix by setting SCRIPT_NAME in the WSGI environment:

class PrefixMiddleware:
    """Middleware to handle subdirectory deployments"""
    def __init__(self, app, prefix=''):
        self.app = app
        self.prefix = prefix.rstrip('/')
        
    def __call__(self, environ, start_response):
        if self.prefix and self.prefix != '/':
            path = environ.get('PATH_INFO', '')
            script_name = environ.get('SCRIPT_NAME', '')
            
            if not script_name.startswith(self.prefix):
                environ['SCRIPT_NAME'] = self.prefix + script_name
                if path.startswith(self.prefix):
                    environ['PATH_INFO'] = path[len(self.prefix):]
        
        return self.app(environ, start_response)

This is automatically applied when APPLICATION_ROOT is set.

2. Updated passenger_wsgi.py

Sets the APPLICATION_ROOT environment variable before importing the app:

if 'APPLICATION_ROOT' not in os.environ:
    os.environ['APPLICATION_ROOT'] = '/product-finder'

3. Updated config.py

Production configuration now defaults to /product-finder:

class ProductionConfig(Config):
    APPLICATION_ROOT = os.environ.get('APPLICATION_ROOT', '/product-finder')

Development still uses / for local testing.

📤 Files to Upload

Upload these updated files to your server:

  1. app/app.py - Contains PrefixMiddleware
  2. app/passenger_wsgi.py - Sets APPLICATION_ROOT env var
  3. app/config.py - Production defaults to /product-finder
  4. app/.htaccess - Apache configuration (new file)
  5. All template files - Already updated with url_for() and BASE_URL

🔧 Server Configuration

The .htaccess file is already configured for /product-finder. Upload it to your app/ folder on the server.

Important: Update these lines in .htaccess:

PassengerAppRoot /home/USERNAME/public_html/product-finder
PassengerPython /usr/bin/python3  # Update to your Python path

Option B: Apache Virtual Host Configuration

If you have access to Apache config, add this to your virtual host:

<Directory "/home/USERNAME/public_html/product-finder">
    SetEnv APPLICATION_ROOT /product-finder
    PassengerEnabled on
    PassengerAppRoot /home/USERNAME/public_html/product-finder
    PassengerPython /usr/bin/python3
    Allow from all
    Options -MultiViews
</Directory>

🚀 Deployment Steps

  1. Backup Current Installation

    mv product-finder product-finder.backup
    
  2. Upload Updated Files

    • Upload entire app/ folder to server
    • Or just upload the 5 changed files listed above
  3. Restart Passenger

    # In product-finder folder
    mkdir -p tmp
    touch tmp/restart.txt
    
  4. Test the Application

    • Go to: https://columbiawindows.com/product-finder/
    • Should redirect to: https://columbiawindows.com/product-finder/login
    • Login page should load with all CSS/JS
    • Login should work and redirect properly
    • All routes should work: /product-finder/users, etc.

🐛 Troubleshooting

Issue: Still getting 404 on login page

Check server error logs:

tail -f ~/logs/error_log  # or wherever your error logs are

Verify APPLICATION_ROOT is set: Add this test route to app.py temporarily:

@app.route('/debug-config')
def debug_config():
    return jsonify({
        'APPLICATION_ROOT': app.config.get('APPLICATION_ROOT'),
        'script_root': request.script_root,
        'url_root': request.url_root,
        'base_url': request.base_url
    })

Then visit: https://columbiawindows.com/product-finder/debug-config

Expected response:

{
  "APPLICATION_ROOT": "/product-finder",
  "script_root": "/product-finder",
  "url_root": "https://columbiawindows.com/product-finder/",
  "base_url": "https://columbiawindows.com/product-finder/debug-config"
}

Issue: CSS/JS files not loading

Check that routes are working:

  • Visit: https://columbiawindows.com/product-finder/css/styles.css
  • Should return CSS file, not 404

Check .htaccess MIME types: Ensure these lines are in .htaccess:

AddType text/css .css
AddType application/javascript .js
AddType application/json .json

Issue: Login works but redirects are wrong

Check redirect code in templates: All JavaScript should use BASE_URL:

const BASE_URL = '{{ base_url }}';
window.location.href = BASE_URL + '/login';

All Python redirects should use url_for():

return redirect(url_for('login_page'))

Issue: Works locally, fails on server

Verify environment:

# SSH to server
cd ~/public_html/product-finder
python3 -c "import os; print(os.environ.get('APPLICATION_ROOT', 'NOT SET'))"

Should print: /product-finder

Check Passenger is using correct Python:

which python3
# Use this path in PassengerPython directive

Issue: Sessions not persisting

Check SECRET_KEY:

# In config.py, production should have a fixed SECRET_KEY
SECRET_KEY = 'your-fixed-secret-key-here'  # Don't use secrets.token_hex() in production

Check cookie settings: Session cookies need to work with the subdirectory path.

Issue: API calls return 404

Check browser console: Press F12, go to Network tab, and check the actual URLs being called.

Should see:

https://columbiawindows.com/product-finder/api/login
https://columbiawindows.com/product-finder/api/session

If you see:

https://columbiawindows.com/api/login  ❌ Missing prefix

Then BASE_URL is not set correctly in template.

Verification Checklist

After deployment, test these in order:

  • Visit https://columbiawindows.com/product-finder/

    • Should redirect to /product-finder/login
  • Login page loads

    • CSS styled correctly ✓
    • No 404s in browser console ✓
  • Login with Master/Master

    • Should redirect to /product-finder/select-location
  • Select a location

    • Should redirect to /product-finder/
  • User info shows in header ✓

  • Click "User Management" (if Master user)

    • Should go to /product-finder/users
  • Logout

    • Should return to /product-finder/login

📝 Key Points

  1. The middleware is critical - It tells Flask about the /product-finder prefix
  2. passenger_wsgi.py sets the env var - Before importing the app
  3. All templates use BASE_URL - For JavaScript fetch calls
  4. All routes use url_for() - For Python redirects
  5. Production config defaults to /product-finder - Development stays at /

🔄 Rolling Back

If something goes wrong:

# Remove new files
rm -rf product-finder

# Restore backup
mv product-finder.backup product-finder

# Restart Passenger
touch product-finder/tmp/restart.txt

📞 Still Having Issues?

Run this diagnostic script on the server:

# Save as test_deployment.py in product-finder folder
import os
import sys

print("=" * 60)
print("DEPLOYMENT DIAGNOSTIC")
print("=" * 60)
print(f"Python Version: {sys.version}")
print(f"Current Directory: {os.getcwd()}")
print(f"APPLICATION_ROOT env: {os.environ.get('APPLICATION_ROOT', 'NOT SET')}")
print()

try:
    os.environ['APPLICATION_ROOT'] = '/product-finder'
    from app import app
    print("✓ App imported successfully")
    print(f"APPLICATION_ROOT config: {app.config.get('APPLICATION_ROOT')}")
    print(f"Middleware applied: {'PrefixMiddleware' in str(type(app.wsgi_app))}")
except Exception as e:
    print(f"✗ Error importing app: {e}")
    import traceback
    traceback.print_exc()

Run with: python3 test_deployment.py

🎯 Expected Behavior

Before these changes:

  • Redirect works: /product-finder/product-finder/login
  • Login page loads BUT Flask doesn't know about /product-finder prefix
  • All url_for() calls generate /login instead of /product-finder/login
  • Result: 404 errors on subpages

After these changes:

  • Flask knows it's at /product-finder via middleware ✓
  • All url_for() generates /product-finder/login
  • All templates use BASE_URL = '/product-finder'
  • Result: Everything works ✓

🆘 Quick Fix Checklist

If deployed and not working:

  1. Uploaded app/app.py with PrefixMiddleware?
  2. Uploaded app/passenger_wsgi.py with env var setting?
  3. Uploaded app/.htaccess with SetEnv directive?
  4. Ran touch tmp/restart.txt to restart Passenger?
  5. Checked error logs for Python errors?
  6. Tested /product-finder/debug-config route?
  7. Verified cookies are being set (F12 > Application > Cookies)?

If all checked and still failing, check server error logs for the actual Python error.