Cloud Functions

54 serverless functions in a single functions/index.js file (~11,500 lines)

At a Glance

18
Firestore Triggers
11
Callable Functions
5
HTTP Endpoints
14
Scheduled Jobs
4
PubSub Handlers

Shared Helpers

HelperPurpose
writeNotification(db, { ... })NEW Writes to Notifications collection. Any cloud function can call it to create in-app alerts. Accepts: type, group, cloudFunction, subject, message (HTML), optional invoiceID/clientID/containerID/metadata. Silently catches errors so it never crashes the caller.

Firestore Triggers (18)

Auto-fire on Firestore document create, update, or write events.

Package Triggers (7)

FunctionEventPurpose
onPackageCheckInonWriteCore invoice engine — creates/updates invoices on check-in. 3 branches based on status + containerID.
updatePackageStatusInContaineronUpdateSyncs package status to Container document's invoices array
onPackageUpdateonUpdateRecalculates invoice when charges/dimensions/itemID change
updateInvoiceOnPackageStatusChangeonUpdateUpdates status in invoice + sets isAllUnloaded. 5 retries with jitter (was 3 retries, fixed March 31).
validateNewPackageClientIDonCreateValidates clientID exists; marks "No Name" problem if not
unloadedNotCheckedInonCreateAlerts when package is unloaded but was never checked in
detectDuplicatePackageonCreateFinds duplicate tracking numbers, sends detailed HTML email + JSON

Invoice Triggers (6)

FunctionEventPurpose
handlePackageStatusChangeonUpdateRemoves packages from invoice when status reverts. 3-min race condition guard.
updateInvoiceStatusInPackagesonUpdateBack-syncs invoice status into all related packages
handlePackageAdditiononUpdateDeduplicates packages, handles consolidation, recalculates totals
handleInvoiceCreationonCreateAuto-approves if all packages have no notes/photos/problems
handleInvoiceUpdateonUpdateRe-checks auto-approve on package array changes
enqueueInvoiceForProcessingonUpdatePublishes to PubSub when APPROVED + ready. 8GB, 540s, max 50.

Client, Container & Log Triggers (5)

FunctionCollectionPurpose
updateSquareCustomerIdInInvoicesClientsSyncs squareCustomerId to all client's invoices
onContainerCreatedContainersPublishes to PubSub after 1-min delay. 8GB, 540s.
prepaidSendEmailContainersGenerates XLSX space report for 21 prepaid clients. 4GB, 540s.
copyDataOnNewContainerContainersArchives 8th-to-last container to secondary DB. 8GB, 540s.
badScanAlertwebLogsSends email with scan details + photo on bad scans

Callable Functions (11)

Invoked from the Flutter app via Firebase Callable SDK.

FunctionMemoryPurpose
loadToContainer8GBLoads all checkIn packages into container, sets inTransit. Batches of 125.
addContainerIdToConsolidatedPackages8GBAdds containerID to sub-packages in containsPackages arrays
sendInvoiceToSquaredefaultManual Square invoice send. Creates Order + Invoice.
updateClientInSquaredefaultSends client updates to n8n webhook
addClientViaWebhookdefaultCreates client via n8n webhook, returns squareCustomerId
approveInvoices8GBBatch approve invoices. Limit: 450 operations.
unapproveInvoices8GBBatch unapprove invoices. Limit: 450 operations.
deleteClientFromSquaredefaultDeletes customer from Square API
splitInvoicedefaultSplits invoice by unloaded vs not-unloaded packages. Now sets isAllUnloaded: true on original (fixed March 31).
startNoPasswordPerioddefaultSets 10-minute no-password window in Temp/timer
sendForceUnloadEmaildefaultAlerts on force-unloaded packages (Roatan timezone)

HTTP Endpoints (5)

FunctionMethodPurpose
trackPackageGETPublic tracking API. ?trackingNumber=...
countTrackPackagesGETClient package counts by status. ?referenceId=... or ?email=...
sendFormattedEmailWithDataGETSends branded status email. ?clientID=...&containerID=...&test=0/1/2
addClientContactPOSTAdd email/phone by referenceId
reportDuplicateLastNamePOSTDuplicate last name alert from signup form

Scheduled Jobs (14)

FunctionSchedulePurpose
resetPasswordExpiryEvery 1 minResets password expiry timer
reconcileStuckInvoicesNEW 5am PH Daily safety net: checks last 3 containers for invoices with stale cached statuses, fixes mismatches, writes notifications. 256MB, 300s.
scheduledFirestoreExportMon-Fri 1pm,8pm ETBackup to gs://maxproductionbackup/
scheduledFirestoreExportWeekendsSat-Sun every 2hrsWeekend backup to gs://maxproductionbackup/
scheduledFirestoreExport2Daily 1pm ETWeekly bucket (Mon) or daily bucket (Tue-Sun)
checkInvoicesDaily6:55am PHInvoice data quality (8 weeks)
checkPackagesDaily6:55am PHPackage data quality (8 weeks)
checkClientsDaily6:55am PHClient data quality (all)
checkContainersDaily6:55am PHContainer data quality (all)
dailyReportAggregator7am PHAggregates check results, emails devs
dailyDataReport1pm PHFull daily ops report to staff
weeklyLostPackagesEmailThu 7am PHLost packages report
weeklyUnloadedNotCheckedInEmailFri 7am ETUnloaded-not-checked-in report
dailyMissingContactsEmailThu 7am ETClients missing email/phone

PubSub Handlers (4)

FunctionTopicPurpose
processInvoiceFromQueueprocess-invoiceSends invoice to Square. Max 3 instances. Retry queue on failure.
processContainerTaskJsonprocess-container-tasksEmails JSON reports (unprocessed, loaded, invoices)
processContainerTaskXslprocess-container-tasksEmails XLSX reports + saves to Storage
processContainerTaskJsonForAppprocess-container-tasksSaves packages JSON to Storage for app

External Integrations

Square API
Payment processing: create orders, invoices, delete customers. Rate-limited.
n8n Webhooks
Client CRUD: create/update clients via Square integration webhooks.
Gmail SMTP
15+ email types via Hostinger SMTP. Alerts, reports, client notifications.
Google Firestore Export
Automated backups: 3 GCS buckets (primary, weekly, daily).
Cloud PubSub
2 topics: process-invoice (1 consumer), process-container-tasks (3 consumers).
Archive DB
Secondary Firestore for long-term archival of old container data.

Notifications SystemNEW

Cloud functions can write in-app notifications via writeNotification(). These appear in the MaxTracks Web dashboard (bell icon, side panel, full page).

FieldRequiredDescription
typeYeserror, alert, reconciliation, info
groupYesinvoices, packages, clients, containers, system
cloudFunctionYesWhich function created it
subjectYesShort title (<80 chars)
messageYesHTML body
invoiceID / clientID / containerIDNoFor filtering & deep linking

Currently used by: reconcileStuckInvoices. Designed to be adopted by all cloud functions over time.

Key Business Rules

Tax: 15%
Applied as "Fee" (customs/duty) on all invoices sent to Square
11 Discount Codes
Location-based (Utila 10%, Guanaja 10%, etc.), VIP 25%, Donations 30%, Prepaid 100%
Retry Queue
In-memory, 3 attempts, 5-min base delay, exponential backoff
7 Locations
Roatan, Utila, La Ceiba, Guanaja, Barbareta, Tegucigalpa, SAP

Deploy

CommandPurpose
firebase use --add max-productionSwitch to production project
firebase deploy --only functionsDeploy all 54 functions
firebase deploy --only functions:functionNameDeploy a single function
firebase functions:logView function logs
firebase emulators:startRun local emulators (port 5001)
📖 Deep dive: Database Schema | March 2026 Changelog | System Overview
← Back to MaxShipping