Spaces:
Runtime error
SDR Status Tracker
Overview
Interactive SDR (Sales Development Representative) activity tracker dashboard. FastAPI backend fetches data from Google Sheets and serves a vanilla JS frontend with leaderboards and progress tables. Built for ScaleupXQ - a B2B sales consulting company.
Project Structure
sdr-status-tracker-v2/
βββ app.py # FastAPI backend (API routes, Google Sheets integration, caching)
βββ excel_parser.py # Excel file parser (local fallback when Sheets unavailable)
βββ detect_columns.py # Auto-detects column layout from sheet headers β column_config.json
βββ static/
β βββ index.html # Frontend dashboard (vanilla HTML/CSS/JS, progress tables)
βββ data/ # Local Excel files for offline/fallback use (gitignored)
βββ months_config.json # Month definitions (sheet IDs, tab names, start_week)
βββ column_config.json # Column layout mapping (weekly + monthly positions)
βββ credentials.json # Google service account key (gitignored β do NOT commit)
βββ SETUP_SECRETS.md # Instructions for setting up secrets (gitignored)
βββ requirements.txt # Python dependencies
βββ Dockerfile # Production container (python:3.11-slim + uvicorn)
βββ README.md # HuggingFace Space config + description
βββ CLAUDE.md # This file - development context
βββ DEVELOPMENT.md # Technical details and customization guide
βββ BRAND_GUIDELINES.md # ScaleupXQ brand identity guide
Brand Guidelines
IMPORTANT: All UI changes must follow the ScaleupXQ brand guidelines in BRAND_GUIDELINES.md.
Key brand elements:
- Primary Color:
#6D3EF3(purple) - Font: Inter (Google Fonts)
- Tone: Bold, engaging, playfully authentic
Deployment
- Live URL: https://huggingface.co/spaces/ScaleupXQ/big-screen-2
- Platform: Hugging Face Spaces (Docker SDK)
- Deploy command:
git push sxq2 main - IMPORTANT: Always push after making changes!
Tech Stack
- Backend: FastAPI (Python 3.11), served via uvicorn
- Data Source: Google Sheets API (primary), Excel files via openpyxl (fallback)
- Frontend: Vanilla HTML/CSS/JavaScript in
static/index.html - Styling: CSS custom properties, gradients, glassmorphism, HTML progress bars
- Real-time: Server-Sent Events (SSE) for live refresh on data changes
- Caching: In-memory per-month cache with 1-hour TTL, webhook invalidation
Data Flow
Google Sheets β FastAPI /api/data β JSON β Frontend fetch β Tables + Leaderboard
β cache (1h TTL)
β webhook invalidation via /api/invalidate-cache
The frontend calls /api/data?month=2026-02 on load and on month selector change. The backend fetches from Google Sheets (or cache), parses the DAILY tab into per-SDR activity blocks, and returns JSON with weekly + monthly totals.
API Endpoints
| Endpoint | Method | Description |
|---|---|---|
/ |
GET | Serve static/index.html |
/api/data?month=ID |
GET | Fetch parsed case data for a month |
/api/months |
GET | List available months for dropdown |
/api/config |
GET | Current sheet configuration |
/api/column-config |
GET | Current column layout |
/api/cache-status |
GET | Cache age and TTL info |
/api/invalidate-cache |
POST | Clear cache (webhook or refresh button) |
/api/reload-config |
POST | Reload column_config.json + months_config.json |
/api/events |
GET | SSE stream for real-time refresh |
/api/debug?month=ID |
GET | Raw sheet data and parsed blocks (debugging) |
Data Structure
Source: Google Sheets
Each month has its own Google Sheet (or tab). The DAILY tab has this layout:
- Column A: Case name (merged cells)
- Column B: GS/SDR name (merged cells)
- Column C: Activity type (Calls, Emails, LinkedIn, Prospects, Discovery, SQL)
- Columns D onwards: Weekly blocks (5 daily columns + target + percentage), then monthly totals
Configuration Files
months_config.json β defines available months:
{
"months": [
{"id": "2026-02", "label": "February 2026", "sheet_id": "...", "tab_name": "DAILY - for SDR to add dataπ", "start_week": 6}
],
"default_month": "2026-02"
}
column_config.json β maps column positions for weekly/monthly data:
{
"weeks": [
{"week_num": 2, "daily_start": 3, "daily_end": 7, "target_col": 8, "pct_col": 9}
],
"monthly": {"target_col": 32, "actual_col": 33, "pct_col": 34}
}
Scoring System (Leaderboard)
Capping Rule (IMPORTANT)
You cannot reach 100% unless ALL individual targets are met. Each target gets an equal share of 100%. If any target is below 100%, over-performance on other targets is capped. Only when ALL targets are >= 100% does over-performance count.
Example with 4 targets (25% share each):
- If targets are 120%, 80%, 100%, 110% β Score is capped: 25 + 20 + 25 + 25 = 95%
- If targets are 120%, 100%, 100%, 110% β All met, uncapped: 30 + 25 + 25 + 27.5 = 107.5%
Legacy Points (not currently used)
- Won (Vunnet): 3 points
- Offer Sent (Tilbud sendt): 2 points
- Meeting Booked (MΓΈte booket): 1 point
Color Scheme (ScaleupXQ Brand)
/* Primary */
--primary: #6D3EF3; /* ScaleupXQ Purple - headers, highlights */
--primary-dark: #602DF2; /* Darker variant - hover states */
/* Status colors from brand palette */
--success: #70E0B1; /* Emerald 300 - won deals, positive */
--warning: #FFF09B; /* Marigold 300 - pending/offers */
--danger: #FF8474; /* Tangerine 300 - lost deals */
--info: #ABECFA; /* Zodiac 300 - informational */
--purple: #B89EFF; /* Lilac 300 - accents */
/* Backgrounds */
--bg-dark: #0D0B13; /* Base 600 - dark background */
See BRAND_GUIDELINES.md for complete color palette and usage rules.
Common Tasks
Add a new month
- Add entry to
months_config.jsonwithid,label,sheet_id,tab_name,start_week - Update
default_monthif it should be the default - If column layout differs, run
python detect_columns.pyto regeneratecolumn_config.json - Deploy:
git push sxq2 main
Change column layout
Run python detect_columns.py (reads sheet headers via Google Sheets API) or edit column_config.json manually. Hit POST /api/reload-config to apply without restart.
Local development
pip install -r requirements.txt
# Set GOOGLE_CREDENTIALS env var (JSON string of service account key)
python app.py # Starts on http://localhost:7860
Modify progress bar / table colors
Edit the CSS custom properties and progress bar color thresholds in static/index.html. See BRAND_GUIDELINES.md for the approved color palette.
Change leaderboard scoring
Edit the scoring logic in static/index.html β the capping rule is implemented in the frontend.
Environment Variables
| Variable | Required | Description |
|---|---|---|
GOOGLE_CREDENTIALS |
Yes | Service account JSON key (as string) |
GOOGLE_SHEET_ID |
No | Default sheet ID (fallback if no months_config.json) |
GOOGLE_SHEET_GID |
No | Default tab/sheet GID (fallback, default 1864606926) |
WEBHOOK_SECRET |
No | Optional secret for cache invalidation webhook |
Git Remotes
sxq: https://huggingface.co/spaces/ScaleupXQ/big-screen (legacy)
sxq2: https://huggingface.co/spaces/ScaleupXQ/big-screen-2 (current)
Deploy command: git push sxq2 main