Deploying a Receipts Management System for quickdumpnow.com and Automating Port Sheet Distribution
What Was Done
This session involved two parallel infrastructure projects: (1) deploying a receipts management landing page for the quickdumpnow.com trailer rental business, and (2) completing the automation pipeline for the JADA Port Log, including calendar token refresh and email distribution.
QuickDumpNow Books/Receipts Page Deployment
The quickdumpnow.com domain needed a dedicated endpoint at /books to serve as the entry point for trailer rental receipts. The page existed locally but had never been deployed to production.
Problem: CloudFront Custom Error Responses
When accessing https://quickdumpnow.com/books, CloudFront was returning the homepage instead of the receipts page. This was caused by a custom error response configuration on the CloudFront distribution that redirects all 404 errors to the root index.html. While this is useful for single-page applications, it prevented pretty URLs from working correctly.
The distribution was configured with:
- Origin pointing to S3 bucket for quickdumpnow.com
- Custom error response: 404 → /index.html (origin response)
- No specific behavior rule for
/books*paths
Solution: Dual S3 Object Upload with CloudFront Invalidation
Rather than modify the CloudFront distribution (which would risk breaking other functionality), we deployed the receipts page to S3 as two separate objects:
s3://quickdumpnow.com/books/index.html
s3://quickdumpnow.com/books
This dual-upload approach ensures that both /books/ (directory-style) and /books (bare path) requests resolve correctly. The file at /Users/cb/Documents/repos/sites/quickdumpnow.com/books/index.html was uploaded with:
- Content-Type:
text/html; charset=utf-8 - Cache-Control:
max-age=3600(1 hour TTL) - CloudFront invalidation patterns:
/booksand/books/*
The robots.txt file at /Users/cb/Documents/repos/sites/quickdumpnow.com/robots.txt was also updated to block this path from search engine crawling, since it serves as an internal receipts system:
Disallow: /books/
CloudFront invalidation took approximately 30–60 seconds to propagate across edge locations.
JADA Port Sheet Automation: Calendar Token and Email Distribution
The port sheet system required two critical fixes: re-establishing Google Calendar API authentication and completing the email distribution pipeline.
OAuth Token Refresh Challenge
The JADA port sheet system reads calendar events from Google Calendar and writes structured data to a Google Sheet (ID: stored in environment). The system had stale OAuth tokens that could no longer refresh. Rather than manually re-authenticate, we built a standalone reauthentication script.
The script at /Users/cb/Documents/repos/tools/reauth_jada_calendar.py implements OAuth 2.0 authorization code flow:
- Reads client credentials from
~/.secrets/google_calendar_client_secret.json - Validates that the client type is
installed(desktop app), notweb - Spins up a local HTTP server on port 8765 to receive the authorization callback
- Constructs the authorization URL with scopes:
calendaranddrive - Prompts user to authorize in browser, then captures the authorization code from the callback
- Exchanges the code for tokens (access + refresh) via the Google token endpoint
- Writes the refresh token to
~/.secrets/GCAL_REFRESH_TOKENfor persistent use
The refresh token is then injected into the AWS Lambda environment as GCAL_REFRESH_TOKEN, allowing scheduled invocations of jada_port_sheet.py to refresh the access token on-the-fly without manual intervention.
Port Log Data Structure and Excel Integration
The JADA Port Log is stored as an Excel file on Google Drive. Unlike simpler spreadsheet formats, the Excel workbook requires precise preservation of multiple sheets, row heights, and column widths. The port sheet template follows a specific structure:
- Month sheet (e.g., "April"): Contains the month name in a specific cell
- Template sheet: Defines headers and formatting for charter entries
- Data rows: Each charter entry includes name, date, vessel, and revenue
To add the latest charter entry ($1,845.72 for a charter yesterday), the system:
- Downloads the current Excel file from Drive using the Google Drive API
- Parses the structure using the
openpyxllibrary (handles.xlsxformat) - Creates or updates the current month sheet
- Appends the entry in the correct row and column format
- Uploads the modified file back to Drive
The jada_port_sheet.py script at /Users/cb/Documents/repos/tools/jada_port_sheet.py handles this end-to-end:
# Pseudocode structure
from openpyxl import load_workbook
from google.oauth2.credentials import Credentials
# Refresh access token using stored refresh_token
creds = refresh_access_token(refresh_token)
# Download and parse Excel
excel_bytes = drive_service.files().get_media(fileId=PORT_LOG_ID).execute()
workbook = load_workbook(io.BytesIO(excel_bytes))
# Add new charter entry
month_sheet = workbook[current_month]
month_sheet.append([charter_name, date, vessel, revenue])
# Upload modified workbook
upload_file_to_drive(PORT_LOG_ID, workbook)
Email Distribution Pipeline
Once the port sheet is updated, the system emails it to stakeholders (Edwin, Maria, Caro) using the Gmail API. The email sender is configured in the Apps Script file at /Users/cb/Documents/repos/sites/queenofsandiego.com/PortSheetReporter.gs.
The script:
- Reads the updated Port Log from Drive
- Formats the current month's data into an email body
- Sends via Gmail with the Excel file as an attachment
- Logs delivery status to the sheet
Infrastructure and Deployment
CloudFront Distribution: The quickdumpnow.com CloudFront distribution has its origin configured to the S3 bucket. Invalidation patterns are managed via the AWS CLI or SDK.
AWS Lambda: The port sheet automation runs on a schedule (CloudWatch Events). Environment variables include