Skip to content

Local Development

Day-to-day development workflow: emulators, testing, linting, dashboard, and git conventions.


Firebase Emulators

The Firebase Emulator Suite lets you run Cloud Functions, Firestore, and Hosting locally without deploying to GCP.

Start the emulators

firebase emulators:start

This starts:

Emulator Port URL
Functions 5001 http://localhost:5001
Firestore 8080 http://localhost:8080
Hosting 5000 http://localhost:5000
Emulator UI 4000 http://localhost:4000

Test against the emulator

With emulators running, send requests to the local function endpoint:

curl -X POST \
  http://localhost:5001/your-gcp-project-id/asia-south1/guvi_honeypot \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_SCAMSHIELD_API_KEY" \
  -d '{
    "sessionId": "local-test-001",
    "currentMessage": {
      "role": "scammer",
      "content": "Sir, your KYC is expiring. Share your Aadhaar number to renew."
    },
    "conversationHistory": []
  }'

Emulator UI

Open http://localhost:4000 in your browser to see the Emulator Suite UI. You can inspect Firestore documents, view function logs, and clear data between test runs.


Running tests

Full test suite

PYTHONPATH=functions pytest tests/ -v

PYTHONPATH is required

Tests import from functions/ (e.g., from guvi.handler import ...). Setting PYTHONPATH=functions ensures Python can resolve these imports.

Run a specific test file

PYTHONPATH=functions pytest tests/guvi/test_extractors.py -v

Run tests matching a pattern

PYTHONPATH=functions pytest tests/ -v -k "test_upi"

Test structure

Tests mirror the source tree:

functions/guvi/handler.py       -->  tests/guvi/test_handler.py
functions/guvi/models.py        -->  tests/guvi/test_models.py
functions/extractors/*.py       -->  tests/guvi/test_extractors.py
functions/engine/orchestrator.py --> tests/engine/test_orchestrator.py

All external services are mocked -- tests never call real APIs, Gemini, Firestore, or GUVI.


Linting and formatting

ScamShield uses ruff for linting and formatting.

Check for lint errors

ruff check functions/ dashboard/ tests/

Auto-fix lint errors

ruff check functions/ dashboard/ tests/ --fix

Format code

ruff format functions/ dashboard/ tests/

Configuration

Linting rules are defined in ruff.toml at the project root:

  • Rules: E (pycodestyle), F (pyflakes), I (isort)
  • Line length: 100 characters
  • Target: Python 3.11

Dashboard local development

The dashboard is a Streamlit app that reads from Firestore and provides session replay, evidence search, analytics, and more.

1. Install dashboard dependencies

pip install -r dashboard/requirements.txt

2. Create a local secrets file

The dashboard reads secrets from .streamlit/secrets.toml. Create it manually for local dev:

mkdir -p dashboard/.streamlit

Create dashboard/.streamlit/secrets.toml:

DASHBOARD_PIN = "123456"

[api]
SCAMSHIELD_API_KEY = "scamshield-your-key-here"

secrets.toml is gitignored

This file is listed in .gitignore. Never commit it. In production, entrypoint.sh generates this file from Cloud Run environment variables at container startup.

3. Run the dashboard

cd dashboard
streamlit run app.py

The dashboard opens at http://localhost:8501. You will be prompted for the PIN you set in secrets.toml.

Firestore connection

The dashboard reads from your GCP Firestore database using Application Default Credentials. Make sure you have authenticated with gcloud auth application-default login so the dashboard can access Firestore data.

Dashboard pages

Page File Description
Home app.py Navigation hub with live metrics
Testing pages/00_testing.py Interactive chat and session replay
Live Sessions pages/01_live_sessions.py Real-time session feed
Evidence pages/02_evidence.py Search and filter evidence
Analytics pages/03_analytics.py Session funnel and charts
Intelligence pages/04_intelligence.py Network graph visualization

Git workflow

Branch strategy

  • main -- production branch. Pushes to main trigger automatic deployment via GitHub Actions.
  • Feature branches -- all development happens on feature branches.

Typical workflow

# Create a feature branch
git checkout -b feature/add-crypto-extractor

# Make changes, run tests
PYTHONPATH=functions pytest tests/ -v

# Lint
ruff check functions/ dashboard/ tests/

# Commit and push
git add -A
git commit -m "Add cryptocurrency wallet address extractor"
git push origin feature/add-crypto-extractor

Then open a pull request to main. The test workflow runs automatically on PRs to main.

CI/CD pipelines

Workflow Trigger What it does
Test (.github/workflows/test.yml) Push to non-main branches, PRs to main Runs pytest tests/ -v
Deploy (.github/workflows/deploy.yml) Push to main, manual dispatch Runs tests, then deploys functions and dashboard

Do not deploy from feature branches

Only main branch deploys to production. The deploy workflow has an explicit if: github.ref == 'refs/heads/main' guard.


Project structure reference

scamshield-ai/
  functions/               # Firebase Cloud Functions (Python 3.11)
    main.py                # Entry point -- exports guvi_honeypot
    guvi/                  # GUVI webhook handler, models, callback
    engine/                # Orchestrator pipeline
    gemini/                # Gemini client and prompt templates
      prompts/
        personas/          # Sharma Uncle, Lakshmi Aunty, Vikram
    extractors/            # Regex-based evidence extraction
    firestore/             # Session storage
    tasks/                 # Cloud Tasks callback scheduler
    utils/                 # Logging, sanitizer, rate limiter, OIDC
    requirements.txt
  dashboard/               # Streamlit dashboard (Cloud Run)
    app.py                 # Dashboard entry point
    pages/                 # Dashboard pages (00-07)
    utils/                 # Auth, Firestore client, display helpers
    requirements.txt
    Dockerfile
    entrypoint.sh
  tests/                   # Test suite (mirrors functions/ structure)
  .github/workflows/       # CI/CD pipelines
  firebase.json            # Firebase project configuration
  firestore.rules          # Firestore security rules
  ruff.toml                # Linter configuration
  setup-wif.sh             # Workload Identity Federation setup
  .env.example             # Environment variable template

Troubleshooting

ModuleNotFoundError when running tests

Make sure you set the Python path:

PYTHONPATH=functions pytest tests/ -v

Emulators fail to start

Check that the required ports (4000, 5000, 5001, 8080) are not in use:

lsof -i :5001
lsof -i :8080

Kill any conflicting processes, or change the ports in firebase.json under emulators.

Dashboard shows "Missing secrets" error

Make sure dashboard/.streamlit/secrets.toml exists and contains the required keys. See the dashboard setup section above.

Firestore permission denied in dashboard

Run gcloud auth application-default login to set up Application Default Credentials. The dashboard uses these to authenticate with Firestore.

Deployment fails with "venv not found"

Firebase CLI requires a functions/venv directory. Create it before deploying:

python3.11 -m venv functions/venv
functions/venv/bin/pip install -r functions/requirements.txt
firebase deploy --only functions