feat: Add Showcase Mode to disable all AI/Gemini features#105
Conversation
- Add SHOWCASE_MODE env variable (defaults to true) - Disable all Celery scheduled tasks when in showcase mode - Block all API endpoints that trigger AI tasks: - /api/admin/tasks/* (collect, generate-alerts, etc.) - /api/bluesky/trigger - /api/archive/trigger - /api/notifications/email/batch - Block geocoding endpoints: - /auth/geocode - /api/alerts/regions/search - Add showcase mode checks to services: - analysis.py (Gemini AI) - geocoding_service.py (Google Geocoding) - population_estimator.py (Google reverse geocoding) - Update docker-compose.yml with SHOWCASE_MODE for all services - Add showcase mode banner to admin dev-tools page - Graceful error handling in location onboarding This puts the app in portfolio/demo mode with $0 API costs while keeping all read-only functionality working.
📝 WalkthroughWalkthroughThis PR introduces a "Showcase Mode" feature that gates AI features and external API calls throughout the application. When enabled via the SHOWCASE_MODE environment variable (default true), scheduled tasks are disabled, data collection and geocoding endpoints return 403 Forbidden, services skip external API calls, and the frontend displays a banner explaining the limitations for portfolio demonstration. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
✨ Version Bump PredictionWhen this PR is merged to 1.52.0 → 1.53.0 ( 💡 How to change the version bump typeThe version bump is determined by your commit messages and PR title:
What I analyzed:
Edit your PR title or commit messages to change the bump type. |
🚀 Preview Deployment Ready!Backend: https://api-feat-showcase-mode.private.bluerelief.app Commit: 🔐 AuthenticationDemo Login: Click "Google Sign In" → Use demo auth (no Google account needed) ✨ Version Bump PredictionWhen this PR is merged to main, the version will be bumped: 1.52.0 → 1.53.0 (minor) 💡 How to change the version bump type
Preview will be automatically deleted when PR is closed or merged. |
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
client/components/location-onboarding.tsx (1)
91-95: Add 403 handling tohandleIPLocationfor consistency.The
handleIPLocationfunction calls/auth/geocode(line 91) but doesn't handle 403 responses, unlikehandleManualLocation(line 152). In showcase mode, users attempting IP-based geolocation will see a generic "Failed to detect location from IP" error instead of the helpful showcase mode message available in manual location search. Add a 403 check inhandleIPLocationto show the same user-friendly message about showcase mode unavailability.
🧹 Nitpick comments (4)
email-service/src/templates/logo.ts (1)
10-11: Remove unnecessary trailing blank lines.These extra blank lines at the end of the file appear to be accidental. Most style guides recommend a single trailing newline.
🔎 Suggested fix
export const BASE_URL = 'https://bluerelief.app'; - - - -server/main.py (1)
129-129: Good: Exposing showcase_mode in API version endpoint.This enables clients to detect showcase mode status. Consider having the frontend dev-tools page fetch this value dynamically rather than always displaying the banner, to ensure consistency with the actual server configuration.
client/app/admin/dev-tools/page.tsx (1)
155-169: Consider fetching showcase mode status dynamically.The banner is currently hardcoded to always display. Since the backend exposes
showcase_modevia/api/version, consider fetching this value and conditionally rendering the banner. This ensures the UI accurately reflects the server configuration.🔎 Suggested approach
// Add state for showcase mode const [showcaseMode, setShowcaseMode] = useState<boolean | null>(null); // Fetch in useEffect useEffect(() => { fetch('/api/version') .then(res => res.json()) .then(data => setShowcaseMode(data.showcase_mode)) .catch(() => setShowcaseMode(null)); }, []); // Conditionally render banner {showcaseMode && ( <Card className="border-amber-500/50 bg-amber-500/10"> {/* ... existing content ... */} </Card> )}server/routers/bluesky.py (1)
57-61: Minor: Consider extracting a shared helper for showcase mode checks.This inline check works correctly, but
admin_tasks.pyuses acheck_showcase_mode()helper function. For consistency and DRY, consider extracting a shared utility that can be reused across routers.🔎 Example shared utility
Create a shared utility in a common location (e.g.,
middleware/showcase_mode.py):import os from fastapi import HTTPException SHOWCASE_MODE = os.getenv("SHOWCASE_MODE", "true").lower() == "true" def check_showcase_mode(feature: str = "This feature"): """Raises HTTPException if showcase mode is enabled""" if SHOWCASE_MODE: raise HTTPException( status_code=403, detail=f"🎭 Showcase Mode: {feature} disabled. This app is in portfolio/demo mode.", )Then import and use across routers:
from middleware.showcase_mode import check_showcase_mode @router.post("/trigger") def trigger_collection(include_enhanced: bool = True): check_showcase_mode("Data collection") # ... rest of endpoint
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
client/app/admin/dev-tools/page.tsxclient/components/location-onboarding.tsxdocker-compose.ymlemail-service/src/templates/logo.tsenvironment.exampleserver/celery_app.pyserver/main.pyserver/routers/admin_tasks.pyserver/routers/alerts.pyserver/routers/archive.pyserver/routers/auth.pyserver/routers/bluesky.pyserver/routers/notifications.pyserver/services/analysis.pyserver/services/geocoding_service.pyserver/services/population_estimator.py
🧰 Additional context used
🧬 Code graph analysis (3)
server/routers/archive.py (2)
server/middleware/admin_auth.py (1)
get_current_admin(10-59)server/tasks.py (1)
archive_completed_disasters(421-472)
server/routers/auth.py (1)
server/services/geocoding_service.py (1)
geocode_region(14-77)
client/app/admin/dev-tools/page.tsx (1)
client/components/ui/card.tsx (2)
Card(103-103)CardContent(109-109)
🪛 Ruff (0.14.10)
server/services/geocoding_service.py
70-70: Consider moving this statement to an else block
(TRY300)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build (frontend, client, Dockerfile.prod, bluerelief/frontend)
🔇 Additional comments (14)
client/components/location-onboarding.tsx (1)
152-155: LGTM! Clear error handling for Showcase Mode.The 403 handling provides a helpful message guiding users to alternative location methods.
server/routers/admin_tasks.py (1)
31-42: LGTM! Clean implementation of the showcase mode guard.The helper function provides consistent 403 responses across all guarded endpoints. Reading the environment variable at module load is appropriate since showcase mode is a deployment-level configuration.
docker-compose.yml (1)
53-53: LGTM! Proper environment variable propagation.The
SHOWCASE_MODEvariable is correctly propagated to all services that need it (backend, celery-worker, celery-beat) with a sensible default oftrue.server/main.py (1)
51-51: LGTM! Consistent environment variable parsing.The showcase mode flag is properly exposed in the application scope.
environment.example (1)
15-17: LGTM! Clear documentation for the new environment variable.The comments explain the purpose and behavior well. Default value of
truealigns with the docker-compose configuration.server/routers/bluesky.py (1)
11-12: LGTM! Showcase mode guard for data collection trigger.The implementation correctly blocks the data collection trigger while keeping read-only endpoints accessible.
server/services/population_estimator.py (1)
13-14: LGTM! Clean showcase mode integration.The SHOWCASE_MODE flag correctly gates Google API calls while preserving fallback behavior to base estimates. The conditional logic on line 81-86 is well-structured and the comment clearly documents the intent.
Also applies to: 80-86
server/routers/alerts.py (1)
12-13: LGTM! Proper endpoint gating with clear user feedback.The showcase mode guard correctly blocks the geocoding endpoint and provides a clear, user-friendly error message explaining the limitation and suggesting alternatives.
Also applies to: 293-298
server/routers/auth.py (1)
29-30: LGTM! Well-placed guard with helpful error messaging.The SHOWCASE_MODE check appropriately blocks geocoding before any processing occurs. The error message is particularly helpful by suggesting alternatives (IP-based location or skip location setup).
Also applies to: 677-682
server/routers/archive.py (1)
11-12: LGTM! Consistent task trigger gating.The showcase mode guard correctly prevents manual archive task triggers while still allowing status checks. This aligns with the pattern of disabling task execution but maintaining read-only access.
Also applies to: 50-54
server/services/geocoding_service.py (1)
10-11: LGTM! Clean early-return pattern.The SHOWCASE_MODE guard is optimally placed before any API key validation or network calls, with clear logging. The early return approach is cleaner than deeply nested conditionals.
Note: The static analysis hint (TRY300) on line 70 is a minor style preference and doesn't affect correctness.
Also applies to: 25-28
server/services/analysis.py (1)
18-19: LGTM! Effective AI feature gating.Both
analyze_postsandanalyze_sentimentcorrectly return empty results before any Gemini API configuration or calls occur. The early returns prevent all AI processing costs while maintaining type-safe return values.Also applies to: 350-353, 519-522
server/routers/notifications.py (1)
20-21: LGTM! Selective email gating.The showcase mode correctly blocks only batch email processing (which would be triggered by automated tasks) while leaving individual email endpoints functional for testing. This is a sensible balance for demo/portfolio mode.
Also applies to: 231-235
server/celery_app.py (1)
10-11: LGTM! Proper scheduled task gating at the beat scheduler level.The conditional beat_schedule setup correctly disables all automatic task execution when showcase mode is enabled, with clear logging on line 54. This is the right architectural approach—stopping tasks at the scheduler rather than inside task logic. The default
SHOWCASE_MODE=trueis intentional and confirmed across environment.example and docker-compose.yml, which aligns with the portfolio/demo focus. Production deployments should explicitly setSHOWCASE_MODE=falseto re-enable full task execution.
Summary
Adds a Showcase Mode that disables all AI/Gemini features and geocoding to bring API costs to $0 while keeping the app functional for portfolio demonstration.
Changes
New Environment Variable
SHOWCASE_MODE- defaults totrue(all AI features disabled)falseto re-enable AI featuresBackend - Celery Scheduled Tasks
Backend - API Endpoints Blocked (11 total)
POST /api/admin/tasks/collectPOST /api/admin/tasks/generate-alertsPOST /api/admin/tasks/process-queuePOST /api/admin/tasks/cleanup-alertsPOST /api/admin/tasks/archivePOST /api/admin/tasks/trigger-test-alertPOST /api/bluesky/triggerPOST /api/archive/triggerPOST /api/notifications/email/batchGET /auth/geocodeGET /api/alerts/regions/searchBackend - Services Protected
analysis.py- Gemini AI analysis blockedgeocoding_service.py- Google Geocoding blockedpopulation_estimator.py- Google reverse geocoding blockedFrontend
Configuration
docker-compose.yml- AddedSHOWCASE_MODEto backend, celery-worker, celery-beatenvironment.example- Documented the new variable/api/version- Now exposesshowcase_modestatusWhat Still Works
✅ User authentication (Google OAuth)
✅ Dashboard viewing existing data
✅ Map visualization
✅ Analysis page (with existing data)
✅ Data feed viewing
✅ Admin panel (viewing only)
✅ IP-based location detection
✅ Skip location setup option
Testing
/api/versionreturns"showcase_mode": trueSummary by CodeRabbit
Release Notes
New Features
Bug Fixes
✏️ Tip: You can customize this high-level summary in your review settings.