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¶
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 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¶
Run tests matching a pattern¶
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¶
Auto-fix lint errors¶
Format code¶
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¶
2. Create a local secrets file¶
The dashboard reads secrets from .streamlit/secrets.toml. Create it manually for local dev:
Create dashboard/.streamlit/secrets.toml:
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¶
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 tomaintrigger 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:
Emulators fail to start¶
Check that the required ports (4000, 5000, 5001, 8080) are not in use:
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: