Skip to content

feat: Add Showcase Mode to disable all AI/Gemini features#105

Merged
geeth24 merged 1 commit into
mainfrom
feat/showcase-mode
Dec 25, 2025
Merged

feat: Add Showcase Mode to disable all AI/Gemini features#105
geeth24 merged 1 commit into
mainfrom
feat/showcase-mode

Conversation

@geeth24

@geeth24 geeth24 commented Dec 25, 2025

Copy link
Copy Markdown
Contributor

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 to true (all AI features disabled)
  • Set to false to re-enable AI features

Backend - Celery Scheduled Tasks

  • All scheduled tasks disabled when showcase mode is enabled
  • Affects: data collection, alert generation, email sending, cleanup, archiving

Backend - API Endpoints Blocked (11 total)

Endpoint Description
POST /api/admin/tasks/collect Data collection
POST /api/admin/tasks/generate-alerts Alert generation
POST /api/admin/tasks/process-queue Queue processing
POST /api/admin/tasks/cleanup-alerts Alert cleanup
POST /api/admin/tasks/archive Archive task
POST /api/admin/tasks/trigger-test-alert Test alerts
POST /api/bluesky/trigger Bluesky data collection
POST /api/archive/trigger Archive trigger
POST /api/notifications/email/batch Batch emails
GET /auth/geocode Location geocoding
GET /api/alerts/regions/search Region search

Backend - Services Protected

  • analysis.py - Gemini AI analysis blocked
  • geocoding_service.py - Google Geocoding blocked
  • population_estimator.py - Google reverse geocoding blocked

Frontend

  • Showcase mode banner added to admin dev-tools page
  • Graceful error handling in location onboarding when geocoding is disabled

Configuration

  • docker-compose.yml - Added SHOWCASE_MODE to backend, celery-worker, celery-beat
  • environment.example - Documented the new variable
  • /api/version - Now exposes showcase_mode status

What 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

  • All endpoints return 403 with showcase mode message when blocked
  • Celery beat shows "SHOWCASE MODE ENABLED" in logs
  • /api/version returns "showcase_mode": true

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Showcase Mode configuration flag to control application behavior.
    • Added visual indicator on admin dev-tools page when Showcase Mode is active.
    • Disabled AI features and certain admin operations when Showcase Mode is enabled.
  • Bug Fixes

    • Improved error messaging for unavailable operations in Showcase Mode.

✏️ Tip: You can customize this high-level summary in your review settings.

- 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.
@geeth24 geeth24 requested review from a team as code owners December 25, 2025 21:58
@coderabbitai

coderabbitai Bot commented Dec 25, 2025

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This 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

Cohort / File(s) Summary
Configuration & Environment Setup
environment.example, docker-compose.yml
Added SHOWCASE_MODE environment variable with default value true and accompanying documentation explaining that AI/Gemini features are disabled in this mode to prevent API costs.
Core Application & Version Endpoint
server/main.py
Exposed SHOWCASE_MODE constant from environment and added showcase_mode field to /api/version endpoint response.
Background Task Scheduling
server/celery_app.py
Conditionally disables all Celery beat scheduled tasks (data collection, alerts, cleanup, archive) when SHOWCASE_MODE is true; prints showcase message and sets beat_schedule to empty dict.
Admin Task Endpoint Guards
server/routers/admin_tasks.py
Added check_showcase_mode() guard function blocking /collect, /generate-alerts, /process-queue, /cleanup-alerts, /archive, /trigger-test-alert endpoints with 403 Forbidden when SHOWCASE_MODE is enabled.
Data Collection & Analysis Services
server/routers/bluesky.py, server/services/analysis.py
Added SHOWCASE_MODE guards to prevent Bluesky data collection trigger and skip Gemini API calls (analyze_posts, analyze_sentiment return empty results in showcase mode).
Geocoding & Location Services
server/routers/alerts.py, server/routers/auth.py, server/services/geocoding_service.py
Added SHOWCASE_MODE guards to disable geocoding API calls and region search, returning 403 Forbidden or None depending on context.
Population & Archive Services
server/services/population_estimator.py, server/routers/archive.py
Added SHOWCASE_MODE checks to skip Google API population lookups and block archive triggering with 403 Forbidden.
Notification Service
server/routers/notifications.py
Added SHOWCASE_MODE guard to block batch email enqueuing with 403 Forbidden.
Frontend UI & Error Handling
client/app/admin/dev-tools/page.tsx, client/components/location-onboarding.tsx
Added "Showcase Mode Active" banner in dev tools page and explicit 403 error handling in location-onboarding to show "manual location search unavailable" message when geocoding is disabled.
Email Template
email-service/src/templates/logo.ts
Trailing whitespace addition only.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

enhancement, version: minor

Suggested reviewers

  • golanu814

Poem

🐰 Hop hop, the showcase mode is here!
Guard the gates, keep APIs clear,
Celery sleeps, no tasks to run,
Demo data shows the work we've done!
Portfolio shines without the cost,
No API calls that would be lost. 🎪

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 56.52% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding Showcase Mode to disable AI/Gemini features, which is the central objective of the PR.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/showcase-mode

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added enhancement New feature or request version: minor ✨ New features - bumps minor version (1.0.0 → 1.1.0) labels Dec 25, 2025
@github-actions

github-actions Bot commented Dec 25, 2025

Copy link
Copy Markdown

✨ Version Bump Prediction

When this PR is merged to main, the version will be bumped:

1.52.01.53.0 (minor)


💡 How to change the version bump type

The version bump is determined by your commit messages and PR title:

  • Major (2.0.0): Use BREAKING CHANGE: or MAJOR: in title/commits
  • Minor (1.53.0): Use feat: or feature: in title/commits
  • Patch (1.52.1): Use fix:, chore:, docs:, etc.

What I analyzed:

  • PR Title: feat: Add Showcase Mode to disable all AI/Gemini features
  • Commits: 1 commit(s)

Edit your PR title or commit messages to change the bump type.

@github-actions github-actions Bot added version: minor ✨ New features - bumps minor version (1.0.0 → 1.1.0) and removed version: minor ✨ New features - bumps minor version (1.0.0 → 1.1.0) labels Dec 25, 2025
@github-actions

Copy link
Copy Markdown

🚀 Preview Deployment Ready!

Backend: https://api-feat-showcase-mode.private.bluerelief.app
Frontend: https://feat-showcase-mode.private.bluerelief.app
Email Service: https://email-api-feat-showcase-mode.private.bluerelief.app

Commit: caca177


🔐 Authentication

Demo Login: Click "Google Sign In" → Use demo auth (no Google account needed)
Demo Account: demo@bluerelief.test
Note: Google OAuth not available for preview domains. Demo mode enabled for testing.


✨ Version Bump Prediction

When this PR is merged to main, the version will be bumped:

1.52.01.53.0 (minor)

💡 How to change the version bump type

  • For patch: Use fix:, chore:, docs:, or ci: in commit messages
  • For minor: Use feat: or feature: in commit messages
  • For major: Include BREAKING CHANGE or breaking: in commit messages

Preview will be automatically deleted when PR is closed or merged.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 to handleIPLocation for consistency.

The handleIPLocation function calls /auth/geocode (line 91) but doesn't handle 403 responses, unlike handleManualLocation (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 in handleIPLocation to 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_mode via /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.py uses a check_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

📥 Commits

Reviewing files that changed from the base of the PR and between 92a399f and a2f4c4c.

📒 Files selected for processing (16)
  • client/app/admin/dev-tools/page.tsx
  • client/components/location-onboarding.tsx
  • docker-compose.yml
  • email-service/src/templates/logo.ts
  • environment.example
  • server/celery_app.py
  • server/main.py
  • server/routers/admin_tasks.py
  • server/routers/alerts.py
  • server/routers/archive.py
  • server/routers/auth.py
  • server/routers/bluesky.py
  • server/routers/notifications.py
  • server/services/analysis.py
  • server/services/geocoding_service.py
  • server/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_MODE variable is correctly propagated to all services that need it (backend, celery-worker, celery-beat) with a sensible default of true.

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 true aligns 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_posts and analyze_sentiment correctly 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=true is intentional and confirmed across environment.example and docker-compose.yml, which aligns with the portfolio/demo focus. Production deployments should explicitly set SHOWCASE_MODE=false to re-enable full task execution.

@geeth24 geeth24 enabled auto-merge (squash) December 25, 2025 22:42
@geeth24 geeth24 merged commit 8531371 into main Dec 25, 2025
10 checks passed
@geeth24 geeth24 deleted the feat/showcase-mode branch December 25, 2025 22:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request version: minor ✨ New features - bumps minor version (1.0.0 → 1.1.0)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants