BGBidGauge Documentation
Updated This page reflects a security-and-infrastructure hardening pass: company-scoped Firestore/Storage rules, admin actions moved behind Cloud Functions, email MFA with remembered devices, a rotating backup/restore system, a real multi-tenant company id, and a staging Firebase project. See Technical Risk Notes for what changed status as a result.

System context

Company users interact with BidGauge entirely through the browser. Cloud Functions now call three external APIs instead of one: ZipTax (sales tax, replacing the earlier Avalara integration), the GSA Travel API (per diem), and the Gmail API (outbound branded email for invites, password resets, and MFA codes).

Company User Admin · Estimator Service Tech SYSTEM BOUNDARY BidGauge React SPA, multi-tenant served via Firebase Hosting Firebase Platform Auth · Firestore · Storage · Scheduler ZipTax sales tax rate lookup GSA Travel API lodging & per-diem rates Gmail API branded invite / reset / MFA email uses (HTTPS) reads / writes data tax lookups* per-diem lookups* invite / reset / MFA email* * all three routed through Cloud Functions, never called directly from the browser

Fig. 1 — System context. Every dependency is still a managed cloud service; the external-API surface grew from two providers to three.

Container diagram

The browser talks directly to Firebase Auth, Firestore, and Storage. Cloud Functions now do meaningfully more than proxy two APIs — they also gate all user-management writes, run the email/MFA pipeline, and run the scheduled backup jobs.

BROWSER React SPA single App() component, ~23.8k lines hand-rolled URL router for deep links resolves company id from the signed-in user's ID token claim Firebase Hosting production + staging targets FIREBASE MANAGED SERVICES Firebase Auth email/password + TOTP MFA custom claim: companyId, bidgaugeEmailMfaByCompany Cloud Firestore companies/{'{'}companyId{'}'}/projects, projectSummaries, itemLibrary, editPresence, databaseBackups, passwordResetRequests, emailLoginVerificationCodes + users/{'{'}uid{'}'} Firebase Storage companies/{'{'}id{'}'}/project-storage/… + database-backups/{'{'}id{'}'}/*.json.gz (scoped by company claim) Cloud Scheduler 3 cron triggers daily / weekly / monthly snapshot jobs sign in / MFA per-collection queries upload / download files CLOUD FUNCTIONS (Node.js 22, us-central1) functions/index.js — 17 exports • 7 user-management callables (create / invite / reset / update / delete / list) • 2 email MFA callables (send / verify code) • 6 backup/recovery callables + scheduled jobs (manual, daily, weekly, monthly, list, restore) • 2 external-data callables (tax, per diem) see Cloud Functions Reference for the full table httpsCallable(...) reads / writes company docs, writes backup metadata invokes on cron schedule gzip snapshot upload EXTERNAL APIS ZipTax ZIPTAX_API_KEY secret GSA Travel API GSA_API_KEY secret Gmail API OAuth refresh token secret Tax/per-diem lookups still cache in Firestore for 30 days. Backups are gzip JSON in Cloud Storage; only metadata lives in Firestore.

Fig. 2 — Containers. Cloud Functions is no longer a thin proxy — it's now the enforcement point for user management, MFA, and backups.

Multi-tenancy & company identity

BidGauge moved from a single hardcoded company document to a real (if not yet self-service) multi-tenant model:

Technology stack

LayerTechnologyNotes
Frontend frameworkReact 19Still no router library — a hand-rolled path-based URL layer now syncs deep links; see Feature Inventory
Build toolVite 8build, build:production, build:staging modes
HostingFirebase HostingSeparate production and staging targets
AuthFirebase AuthEmail/password, optional Firebase-native TOTP MFA, plus a custom email-code MFA layer with per-company remembered-device claims
DatabaseCloud FirestoreMulti-collection, company-scoped; see Data Model
File storageFirebase StorageProject files, PDFs, and gzip database backups, all company-scoped
Server logicCloud Functions (Node.js 22)17 callables/scheduled functions, up from 4
Scheduled jobsCloud Scheduler (via onSchedule)3 crons driving the rotating backup system
PDF generationpdf-libUnchanged — client-side, hand-built layouts
Spreadsheet/zip/CSVHand-rolled (no library)Unchanged — see Technical Risk Notes
Outbound emailGmail API (raw MIME over fetch)New — invites, password resets, MFA codes; no SMTP/nodemailer library used
Sales tax dataZipTax APIReplaces the earlier Avalara AvaTax integration; cached 30 days
Travel dataGSA Travel Per Diem APIUnchanged, cached 30 days
TestingNode's built-in test runnerNew — one extracted module (src/lib/paymentApplications.js) has real unit tests; the rest of the app remains untested
DocsJSDocNew — npm run docs generates HTML API docs from comments now present in App.jsx and functions/index.js
What changed structurally The single-document data model from the first documentation pass is gone in production. Company data now lives across dedicated collections (projects, projectSummaries, itemLibrary, and more), each company scoped by a Firestore-rules-enforced custom claim. A one-time in-app migration path still runs for any company doc that hasn't been converted yet — see Data Model for the full shape and what's still transitional.