Skip to content

Repository files navigation

Testsigma Revenue Intelligence Hub — Ops Guide

Internal tool for the Testsigma sales and GTM team. Deployed on Vercel at battlecard-nine.vercel.app.


Table of Contents

  1. Architecture Overview
  2. Environment Variables
  3. Firebase Setup & Auth
  4. User Management
  5. Slack Integration
  6. Vercel Blob Storage
  7. API Routes
  8. Cron Jobs
  9. Deploying Changes
  10. Common Issues & Fixes

Architecture Overview

Browser (React SPA)
  ↓ Firebase Google Auth (login)
  ↓ /api/* (Vercel serverless functions)
      ├── Claude (Anthropic) — AI answers + web search
      ├── Gong — call history & transcripts
      ├── Attive — AI analyst for your entire revenue stack (reads CRM, calls, and emails via Slack bot)
      ├── Custify — customer health, usage, renewals
      ├── HubSpot — CRM data
      ├── Salesforce — CRM data
      ├── G2 — buyer intent signals
      ├── Vercel Blob — KB, user groups, analytics cache
      └── Slack — digest, feedback, Attive pings, access requests

Deployment: Push to main → Vercel auto-deploys (typically 2–3 min). Repo: narain-testsigma/battlecard (private) Vercel project: battlecard-nine


Environment Variables

Set all of these in Vercel → Project Settings → Environment Variables. Never commit secrets to the repo.

Backend (API)

Variable Description Where to get it
ANTHROPIC_KEY Claude API key console.anthropic.com → API Keys
GONG_ACCESS_KEY Gong API access key Gong → Settings → API
GONG_SECRET Gong API secret Gong → Settings → API
SLACK_BOT_TOKEN Slack bot token (xoxb-...) api.slack.com → Your App → OAuth Tokens
SLACK_SIGNING_SECRET Validates incoming Slack events api.slack.com → Your App → Basic Info
ATTIVE_API_KEY Attive KB API key Attive dashboard
BCBLOB_READ_WRITE_TOKEN Vercel Blob storage Vercel → Storage → your Blob store
INTERNAL_API_TOKEN Internal auth between frontend ↔ API Generate any random string (32+ chars)
HUBSPOT_TOKEN HubSpot private app token HubSpot → Settings → Integrations → Private Apps
CUSTIFY_API_KEY Custify API key Custify dashboard → API
CUSTIFY_API_URL Custify endpoint https://us.api.custify.com
G2_API_TOKEN G2 intent data G2 Buyer Intent dashboard
FACTORS_API_KEY Factors.ai intent data Factors dashboard
RESEND_API_KEY Transactional email resend.com → API Keys
NOTIFY_EMAIL Where feedback emails go e.g. narain@testsigma.com
GAMMA_API_KEY Gamma deck generation gamma.app
GITHUB_TOKEN Posts feedback as GitHub issues GitHub → Settings → PAT (repo scope)
GITHUB_REPO Target repo for feedback issues e.g. narain-testsigma/sdr-navigator
SHEET_WEBHOOK_URL Google Sheets webhook for analytics Google Apps Script deploy URL
SHEET_SECRET Shared secret for webhook Set same value in Sheets script
SITE_PASSWORD Legacy password auth (fallback) Set any strong password
ADMIN_PASSWORD Legacy admin password auth Set any strong password
APP_URL Public app URL https://battlecard-nine.vercel.app

Frontend (React — must be prefixed REACT_APP_)

Variable Description
REACT_APP_FIREBASE_API_KEY Firebase project API key
REACT_APP_FIREBASE_AUTH_DOMAIN e.g. your-project.firebaseapp.com
REACT_APP_FIREBASE_PROJECT_ID Firebase project ID
REACT_APP_FIREBASE_APP_ID Firebase app ID
REACT_APP_INTERNAL_API_TOKEN Same value as INTERNAL_API_TOKEN above

Note: REACT_APP_* variables are baked into the frontend bundle at build time. Changing them requires a redeploy.


Firebase Setup & Auth

The app uses Firebase Google OAuth — users sign in with their Google account, no passwords.

Allowed domains

Only @testsigma.com and @speargrowth.com emails can log in. Enforced in two places:

  • src/Home.jsxallowedDomains array (frontend check after OAuth)
  • Firebase Console → Authentication → Authorized domains

Firebase Console checklist

  1. Go to console.firebase.google.com
  2. Select the project (same as REACT_APP_FIREBASE_PROJECT_ID)
  3. Authentication → Sign-in method → Google → Enable
  4. Authentication → Authorized domains → Add:
    • battlecard-nine.vercel.app
    • localhost (for local dev)
    • Any preview deployment domains if needed
  5. Project Settings → General → Your apps → get the config values for env vars

Adding a new allowed email domain

Two code changes needed:

  • src/Home.jsxallowedDomains array
  • api/user-groups.jsallowedDomains array (controls who can be added via the admin UI)

Then redeploy.

Request Access flow

Users who sign in but have no tier assigned see a "Request Access" banner with a button. Clicking it posts their name + email to #battlecard-deploy-feedback in Slack so an admin can grant access.


User Management

Tiers

Tier Access
sales Cold Call, Competition Intel, Content Review, Demo Prep, AMA, Learn
csm Everything in sales + Customer Health
admin Everything including Analytics, User Access, Knowledge Base, Hot Accounts, Account 360, Hall of Fame
spear AMA only (for Spear Growth agency users)
marketing Marketing OS and all marketing apps (Ad Copy, Blog Writer, Campaign Planner, etc.)
manager Coaching Dashboard
ceo_office Feedback Loop — admin bypass is disabled; must be explicitly assigned

@testsigma.com accounts automatically get sales tier on first login. @speargrowth.com accounts need to be manually assigned spear tier.

Adding a user

  1. Go to the app → Admin section → User Access
  2. Enter their email (must be @testsigma.com or @speargrowth.com)
  3. Select their tier(s)
  4. Click Add

Changes take effect on their next sign-in.

Removing a user

Same page — click × next to their name.

Spoofing a user (admin only)

Used for testing tier visibility without logging out:

  1. Go to User Access
  2. Click 👁 Spoof next to any user
  3. App reloads showing you exactly what that user sees
  4. Yellow banner at top confirms who you're spoofing
  5. Click Exit spoof to return to your admin view

Spoof is session-only — closes when the tab closes.

User data storage

User → tier mappings are stored in Vercel Blob at config/user-groups.json. Managed entirely through the User Access UI — no manual blob edits needed.


Slack Integration

Slack app config

  • App name: Testsigma Intelligence (or similar)
  • Workspace: Testsigma Slack
  • Needs these OAuth scopes:
    • chat:write — post messages
    • chat:write.public — post to channels without joining
    • channels:history + conversations.replies — read thread replies
    • files:read — read Attive's PDF responses
    • channels:read — list channels
    • users:read — resolve user names

Hardcoded channel/user IDs

ID What it is
C0AB3QJ2VQW #attive-pmm — AMA pings Attive bot here
C098WC88ABD #ai-generated-analysis — KB Intel monitors this
C0987FW4154 #pmm-and-product — KB Intel monitors this
C0ARCJ3SBA7 #battlecard-deploy-feedback — Request Access pings + negative feedback alerts
U09FP9X2M53 Attive bot user ID (the bot that replies with account briefs)

If any of these change (channel renamed, Attive bot reinstalled), update the hardcoded IDs in the relevant api files.

What Attive is

Attive is the AI analyst for your entire revenue stack. It reads your CRM, calls, and emails together — so you can ask why deals are lost, which accounts are at risk, and what your pipeline actually looks like.

How Attive works

When a user asks AMA about an account:

  1. AMA posts @Attive <AccountName> — <question> in #attive-pmm
  2. api/attive-poll.js polls the thread every 3s for up to 55s
  3. Attive replies (text or PDF) — text is extracted and passed to Claude
  4. Claude answers with Attive data as primary source, supplemented by Gong call context

Attive stores accounts by compact name (no spaces): "State Farm" → ping as "Statefarm".

KB capture via Slack (📌 reaction)

Adding a 📌 (pushpin) reaction to any Attive message in Slack saves it to the Knowledge Base:

  • Text messages → saved directly to Google Sheet
  • PDF attachments → Slack DMs the reactor asking them to use /kb-add to paste the content

Vercel Blob Storage

All persistent data lives in Vercel Blob (token: BCBLOB_READ_WRITE_TOKEN).

Blob path Contents Updated by
kb/claude-core.md Main shared knowledge base KB Admin UI or api/kb-admin.js
kb/claude-intel.md Weekly Slack intel summary api/kb-intel.js (cron)
config/user-groups.json User → tier mappings User Access UI
accounts/*.json Cached account intelligence api/account-360.js, api/demo-prep.js
analytics/logs.json Usage analytics log api/analytics.js
hall-of-fame/*.json Hall of Fame entries and reactions api/hall-of-fame.js

To view/edit blobs directly: Vercel dashboard → Storage → your Blob store.


API Routes

Endpoint What it does
POST /api/ama Account context fetch (Attive + Gong) or Claude call with web search. Body: { accountName, question, messages }
POST /api/attive-poll Polls #attive-pmm thread for Attive's reply
GET /api/gong Fetches and caches Gong calls for an account
GET /api/account-360 Full account intel (HubSpot + Gong + G2 + Attive)
POST /api/demo-prep Demo prep brief generation
POST /api/cold-call Live call intelligence
POST /api/content-review Content review against brand standards
GET /api/custify Custify customer health data — all active companies normalised with health scores, ARR, renewal dates, usage metrics
POST /api/job-signals Scans a company's active QA job listings for competing tool expertise (Provar, Tosca, Selenium, Playwright, etc.) using Claude web search
GET /api/g2 G2 buyer intent signals by domain
GET /api/kb Fetches shared KB (claude-core + claude-intel)
POST /api/kb-admin Update claude-core.md knowledge base
POST /api/kb-intel Run Slack intel capture + summarise
GET /api/user-groups List all user → tier mappings, or ?email=x to get tiers for a specific user
POST /api/user-groups Add/update a user's tiers
DELETE /api/user-groups Remove a user
POST /api/analytics Log a usage event
POST /api/slack Slack event handler (signing secret validated) — handles reaction_added (📌), /kb-add slash command, modal submissions, and internal post_message calls
GET /api/slack-digest Triggered by cron — sends daily hot accounts digest to Slack
POST /api/feedback Field feedback → email PMM + GitHub issue
GET /api/gong-calls Recent calls list for Hall of Fame
GET /api/hall-of-fame Hall of Fame entries
POST /api/hall-of-fame Add Hall of Fame entry
GET /api/gamma Generate Gamma deck
POST /api/narrative-pptx Generate PowerPoint narrative
POST /api/auth Legacy password auth
POST /api/event-prep Event prep brief generation. Shareable via public /event-prep/:eventId route
GET /api/history Query usage history log
GET /api/gong-scorecards Gong scorecard data
GET /api/g2-ratings G2 ratings data
GET /api/attive-pdf Fetch and parse Attive PDF attachments from Slack
POST /api/onboarding Onboarding flow handler
GET /api/salesforce Salesforce CRM data

Most API routes require the x-internal-token header matching INTERNAL_API_TOKEN. Exceptions: /api/auth, /api/slack (uses Slack signing secret instead).


Cron Jobs

Defined in vercel.json:

Schedule Route What it does
0 4 * * 1-5 /api/slack-digest Weekdays 4 AM UTC — sends hot accounts digest to Slack

To add a cron: edit vercel.json → push to main. Cron logs are visible in Vercel → Functions → Logs.


Deploying Changes

git add .
git commit -m "describe change"
git push origin main
# Vercel auto-deploys in ~2 min

Watch the build at: vercel.com → battlecard-nine → Deployments

If the build fails: Check the build log for ESLint errors — Vercel treats warnings as errors (CI=true). Common culprits: unused variables, missing dependencies.


Common Issues & Fixes

User can't log in

  • Check their email domain is in allowedDomains in src/Home.jsx
  • Check Firebase Console → Authorized domains includes the app URL
  • Check they've been added to User Access with the right tier
  • If they see a "Request Access" button, they are authenticated but have no tier — add them via User Access

AMA returns "No CRM Record Found"

  • Attive stores accounts without spaces: try "Statefarm" not "State Farm"
  • The ping includes the question now — if still failing, check SLACK_BOT_TOKEN is set and the Attive bot (U09FP9X2M53) is in #attive-pmm

AMA times out / no Gong data

  • Check Vercel function logs for the gong.js extraction step
  • Gong uses a 1-hour module-level cache — a cold start clears it
  • Verify GONG_ACCESS_KEY and GONG_SECRET are set

Attive reply never arrives

  • api/attive-poll.js polls for 55s — Attive can take up to 60s for large accounts
  • Check Vercel logs for Attive poll: got reply after Xs
  • If Attive bot is down or slow, AMA still answers using Gong data only

Customer Health shows 0 companies

  • Check CUSTIFY_API_KEY is set in Vercel environment variables
  • Check Vercel logs for the /api/custify function — will show the raw count vs filtered count
  • The endpoint filters out churned accounts — raw in the response shows the unfiltered count

Customer Health showing all accounts as healthy

  • Health score fields use Salesforce __c suffix — e.g. ghs__c, risk_rating__c
  • risk_rating__c is a string ("Low"/"Medium"/"High"/"Critical"), not a number
  • If fields are empty for all accounts, check Custify custom attribute mappings

Build error: "X is assigned a value but never used"

  • Remove the unused variable — Vercel treats ESLint warnings as errors in CI

KB not updating

  • Go to Admin → Knowledge Base and check the blob editor
  • Or call POST /api/kb-admin with the updated content
  • claude-intel.md is auto-updated by the weekday cron

Spoof mode not working across pages

  • Spoof is stored in sessionStorage — must be same tab
  • Only works if you are an admin — non-admins can't activate spoof

Request Access Slack ping not arriving

  • Check SLACK_BOT_TOKEN is set and has chat:write.public scope
  • Channel ID C0ARCJ3SBA7 is hardcoded in src/Home.jsx — verify it matches #battlecard-deploy-feedback

Job signals scan not working (Hiring Intelligence)

  • Requires ANTHROPIC_KEY and INTERNAL_API_TOKEN set in Vercel
  • Uses Claude web search — max duration is 45s per company, 20 companies scanned in parallel
  • Results are cached in sessionStorage — refresh the page to clear the cache and re-scan

Key Contacts

Role Person
Product / Owner Narain (narain@testsigma.com)
Vercel / GitHub access Narain
Firebase project Narain
Attive bot Attive team

About

No description, website, or topics provided.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages