BGBidGauge Documentation
Resolved from the previous pass "No separate staging environment" was flagged in the first documentation pass. A dedicated staging Firebase project now exists, with its own build mode and deploy targets, so rule/function changes can be verified before touching production.

Firebase projects

// .firebaserc
{
  "projects": {
    "default": "bidgauge",
    "production": "bidgauge",
    "staging": "bidgauge-staging"
  }
}

Live production app: https://bidgauge.web.app (custom domain: https://bidgauge.peerlesscom.com, used for branded email action links — see Cloud Functions Reference).

Firebase project config

// firebase.json
{
  "firestore": { "rules": "firestore.rules" },
  "storage":   { "rules": "storage.rules" },
  "auth":      { "providers": { "emailPassword": true } },
  "functions": { "source": "functions", "runtime": "nodejs22" },
  "hosting": {
    "public": "dist",
    "headers": [
      { "source": "/index.html", "headers": [{ "key": "Cache-Control", "value": "no-cache" }] },
      { "source": "/",           "headers": [{ "key": "Cache-Control", "value": "no-cache" }] },
      { "source": "/assets/**",  "headers": [{ "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }] }
    ],
    "rewrites": [{ "source": "**", "destination": "/index.html" }]
  }
}

New since the last pass: an explicit auth.providers declaration, cache-control headers (long-lived immutable caching for hashed asset files, no-cache for the HTML shell so deploys take effect immediately), and the Functions runtime bumped to nodejs22.

Build & deploy commands

CommandWhat it does
npm run devVite dev server with HMR
npm run buildDefault production build to dist/
npm run build:productionBuild in production Vite mode
npm run build:stagingBuild in staging Vite mode
npm run deploybuild then firebase deploy --only hosting (default project)
npm run deploy:productionbuild:production then a full firebase deploy --project production (hosting, rules, and functions)
npm run deploy:stagingbuild:staging then a full firebase deploy --project staging
npm run deploy:staging:webbuild:staging then a narrower deploy — --only firestore:rules,hosting — for quick front-end/rules-only staging pushes
npm run lintESLint over the project
npm run testNew — runs node --test tests/*.test.mjs (currently one suite, paymentApplications.test.mjs)
npm run verifyNew — scripts/verify.mjs: runs lint → test → build → node --check functions/index.js, stopping at the first failure. A reasonable one-command pre-push gate.
npm run docsNew — generates JSDoc HTML output to docs/ from comments in App.jsx and functions/index.js
npm run hosting:previewDeploys to a Firebase Hosting preview channel

Environment variables (client)

VITE_FIREBASE_API_KEY=
VITE_FIREBASE_AUTH_DOMAIN=
VITE_FIREBASE_PROJECT_ID=
VITE_FIREBASE_STORAGE_BUCKET=
VITE_FIREBASE_MESSAGING_SENDER_ID=
VITE_FIREBASE_APP_ID=
VITE_FIREBASE_MEASUREMENT_ID=
VITE_ENABLE_LIVE_TAX_LOOKUP=false
VITE_BIDGAUGE_COMPANY_ID=   (optional — pre-login fallback only, see note below)

The app still throws on startup if VITE_FIREBASE_PROJECT_ID is missing. Once a user is signed in, the active tenant comes from their own companyId ID token claim, not from this variable — VITE_BIDGAUGE_COMPANY_ID (along with a ?companyId= URL param and localStorage) now only matters for pre-login screens like password setup/reset links, before a token is available. See Architecture.

Secrets (Cloud Functions runtime only — never in client env files)

SecretUsed byNotes
ZIPTAX_API_KEYlookupTaxRateReplaces the earlier Avalara credentials
GSA_API_KEYlookupGsaPerDiemFalls back to the public DEMO_KEY if unset
GMAIL_CLIENT_ID, GMAIL_CLIENT_SECRET, GMAIL_REFRESH_TOKENAll email-sending callablesRefresh token obtained once via scripts/get-gmail-refresh-token.mjs, signed in as info@bidgauge.software
BIDGAUGE_SMTP_PASSWORDNothingProvisioned by scripts/set-bidgauge-smtp-secret.ps1 but unreferenced in code — vestigial, see Technical Risk Notes

Operational scripts

A new scripts/ folder (repo root) and functions/scripts/ folder hold one-off tooling that intentionally isn't wired into any callable or CI step — these are run manually by whoever administers the Firebase project.

ScriptPurpose
scripts/verify.mjsLocal/CI pre-flight gate (lint, test, build, syntax-check functions)
scripts/get-gmail-refresh-token.mjsOne-time interactive OAuth flow to obtain the Gmail API refresh token
scripts/set-bidgauge-smtp-secret.ps1Uploads an SMTP password as a secret — currently dead, nothing consumes it
scripts/disable-security-defaults.mjsUnrelated to Firebase — disables Azure AD "Security Defaults" via Microsoft Graph device-code auth, presumably for a Microsoft-hosted mailbox used elsewhere in the business
functions/scripts/set-company-auth-claims.mjsBulk-assigns the companyId custom claim to every Firebase Auth user (the actual mechanism behind multi-tenancy — see Architecture)
functions/scripts/generate-company-id.mjsMints a new Firestore-style company id for provisioning a second tenant
functions/scripts/migrate-company-id.mjsCopies a company doc + subcollections from one company id to another (used for the "default" → generated-id production migration)
functions/scripts/enable-totp-mfa.mjsEnables Firebase-native TOTP MFA on the project — independent of the custom email-code MFA path
Provisioning a new company today is a manual, ordered process Generate an id → migrate/seed its data → bulk-assign the custom claim to its users → (optionally) deploy company-specific config. There is no in-app "create a new company" flow yet — see Architecture and Technical Risk Notes.

Data & storage config

Previous← Feature Inventory