54 serverless functions in a single functions/index.js file (~11,500 lines)
| Helper | Purpose |
|---|---|
| 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. |
Auto-fire on Firestore document create, update, or write events.
Package Triggers (7)
| Function | Event | Purpose |
|---|---|---|
| onPackageCheckIn | onWrite | Core invoice engine — creates/updates invoices on check-in. 3 branches based on status + containerID. |
| updatePackageStatusInContainer | onUpdate | Syncs package status to Container document's invoices array |
| onPackageUpdate | onUpdate | Recalculates invoice when charges/dimensions/itemID change |
| updateInvoiceOnPackageStatusChange | onUpdate | Updates status in invoice + sets isAllUnloaded. 5 retries with jitter (was 3 retries, fixed March 31). |
| validateNewPackageClientID | onCreate | Validates clientID exists; marks "No Name" problem if not |
| unloadedNotCheckedIn | onCreate | Alerts when package is unloaded but was never checked in |
| detectDuplicatePackage | onCreate | Finds duplicate tracking numbers, sends detailed HTML email + JSON |
Invoice Triggers (6)
| Function | Event | Purpose |
|---|---|---|
| handlePackageStatusChange | onUpdate | Removes packages from invoice when status reverts. 3-min race condition guard. |
| updateInvoiceStatusInPackages | onUpdate | Back-syncs invoice status into all related packages |
| handlePackageAddition | onUpdate | Deduplicates packages, handles consolidation, recalculates totals |
| handleInvoiceCreation | onCreate | Auto-approves if all packages have no notes/photos/problems |
| handleInvoiceUpdate | onUpdate | Re-checks auto-approve on package array changes |
| enqueueInvoiceForProcessing | onUpdate | Publishes to PubSub when APPROVED + ready. 8GB, 540s, max 50. |
Client, Container & Log Triggers (5)
| Function | Collection | Purpose |
|---|---|---|
| updateSquareCustomerIdInInvoices | Clients | Syncs squareCustomerId to all client's invoices |
| onContainerCreated | Containers | Publishes to PubSub after 1-min delay. 8GB, 540s. |
| prepaidSendEmail | Containers | Generates XLSX space report for 21 prepaid clients. 4GB, 540s. |
| copyDataOnNewContainer | Containers | Archives 8th-to-last container to secondary DB. 8GB, 540s. |
| badScanAlert | webLogs | Sends email with scan details + photo on bad scans |
Invoked from the Flutter app via Firebase Callable SDK.
| Function | Memory | Purpose |
|---|---|---|
| loadToContainer | 8GB | Loads all checkIn packages into container, sets inTransit. Batches of 125. |
| addContainerIdToConsolidatedPackages | 8GB | Adds containerID to sub-packages in containsPackages arrays |
| sendInvoiceToSquare | default | Manual Square invoice send. Creates Order + Invoice. |
| updateClientInSquare | default | Sends client updates to n8n webhook |
| addClientViaWebhook | default | Creates client via n8n webhook, returns squareCustomerId |
| approveInvoices | 8GB | Batch approve invoices. Limit: 450 operations. |
| unapproveInvoices | 8GB | Batch unapprove invoices. Limit: 450 operations. |
| deleteClientFromSquare | default | Deletes customer from Square API |
| splitInvoice | default | Splits invoice by unloaded vs not-unloaded packages. Now sets isAllUnloaded: true on original (fixed March 31). |
| startNoPasswordPeriod | default | Sets 10-minute no-password window in Temp/timer |
| sendForceUnloadEmail | default | Alerts on force-unloaded packages (Roatan timezone) |
| Function | Method | Purpose |
|---|---|---|
| trackPackage | GET | Public tracking API. ?trackingNumber=... |
| countTrackPackages | GET | Client package counts by status. ?referenceId=... or ?email=... |
| sendFormattedEmailWithData | GET | Sends branded status email. ?clientID=...&containerID=...&test=0/1/2 |
| addClientContact | POST | Add email/phone by referenceId |
| reportDuplicateLastName | POST | Duplicate last name alert from signup form |
| Function | Schedule | Purpose |
|---|---|---|
| resetPasswordExpiry | Every 1 min | Resets 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. |
| scheduledFirestoreExport | Mon-Fri 1pm,8pm ET | Backup to gs://maxproductionbackup/ |
| scheduledFirestoreExportWeekends | Sat-Sun every 2hrs | Weekend backup to gs://maxproductionbackup/ |
| scheduledFirestoreExport2 | Daily 1pm ET | Weekly bucket (Mon) or daily bucket (Tue-Sun) |
| checkInvoicesDaily | 6:55am PH | Invoice data quality (8 weeks) |
| checkPackagesDaily | 6:55am PH | Package data quality (8 weeks) |
| checkClientsDaily | 6:55am PH | Client data quality (all) |
| checkContainersDaily | 6:55am PH | Container data quality (all) |
| dailyReportAggregator | 7am PH | Aggregates check results, emails devs |
| dailyDataReport | 1pm PH | Full daily ops report to staff |
| weeklyLostPackagesEmail | Thu 7am PH | Lost packages report |
| weeklyUnloadedNotCheckedInEmail | Fri 7am ET | Unloaded-not-checked-in report |
| dailyMissingContactsEmail | Thu 7am ET | Clients missing email/phone |
| Function | Topic | Purpose |
|---|---|---|
| processInvoiceFromQueue | process-invoice | Sends invoice to Square. Max 3 instances. Retry queue on failure. |
| processContainerTaskJson | process-container-tasks | Emails JSON reports (unprocessed, loaded, invoices) |
| processContainerTaskXsl | process-container-tasks | Emails XLSX reports + saves to Storage |
| processContainerTaskJsonForApp | process-container-tasks | Saves packages JSON to Storage for app |
Cloud functions can write in-app notifications via writeNotification(). These appear in the MaxTracks Web dashboard (bell icon, side panel, full page).
| Field | Required | Description |
|---|---|---|
| type | Yes | error, alert, reconciliation, info |
| group | Yes | invoices, packages, clients, containers, system |
| cloudFunction | Yes | Which function created it |
| subject | Yes | Short title (<80 chars) |
| message | Yes | HTML body |
| invoiceID / clientID / containerID | No | For filtering & deep linking |
Currently used by: reconcileStuckInvoices. Designed to be adopted by all cloud functions over time.
| Command | Purpose |
|---|---|
| firebase use --add max-production | Switch to production project |
| firebase deploy --only functions | Deploy all 54 functions |
| firebase deploy --only functions:functionName | Deploy a single function |
| firebase functions:log | View function logs |
| firebase emulators:start | Run local emulators (port 5001) |