Deploying a Receipt Upload System for quickdumpnow.com and Automating Port Sheet Generation with Google Sheets Integration
This session involved two parallel infrastructure projects: standing up a receipt management endpoint for a trailer rental business, and debugging/completing an automated port sheet generation pipeline that integrates Google Drive, Google Sheets, Google Calendar, and AWS Lambda.
Part 1: QuickDumpNow Books Endpoint Deployment
Problem: The domain https://quickdumpnow.com/books was returning the homepage instead of a dedicated receipt upload interface.
Root Cause: The S3 bucket had a custom CloudFront error response configuration (a common pattern for single-page apps) that redirects all 404s to the homepage. The books/index.html file existed locally but hadn't been deployed to S3.
Deployment Process:
- Located the static site files at
/Users/cb/Documents/repos/sites/quickdumpnow.com/ - Updated
books/index.htmlwith the correct model ID reference (the original had a placeholder) - Updated
robots.txtto block the/bookspath from indexing (since this is an internal receipt upload tool, not public-facing content) - Uploaded both
books/index.htmland a barebookskey to the S3 bucket (the bare key ensures CloudFront serves the index for pretty URLs) - Invalidated the CloudFront distribution cache for both
/booksand/books/*paths
Why Two S3 Keys? CloudFront doesn't automatically append index.html the way a traditional web server does. By uploading to both books/index.html (for explicit requests) and a bare books key (for directory-style requests), we ensure the page serves correctly regardless of whether a user requests /books or /books/. This is a common pattern when using S3 + CloudFront for static sites.
Result: Within 30–60 seconds of the CloudFront invalidation, https://quickdumpnow.com/books began serving the dedicated receipt page. The robots.txt exclusion ensures search engines don't index this internal tool.
Part 2: Automated Port Sheet Generation Pipeline
Context: A sailing business (JADA) needed an automated monthly port sheet that compiles charter data, formats it into an Excel workbook, and emails it to stakeholders. The system integrates:
- Google Sheets (Port Log and Charter data)
- Google Drive (source and destination for workbooks)
- Google Calendar (to pull event details)
- AWS Lambda (to run the monthly job)
- Email delivery (via Google Drive/Sheets APIs)
Infrastructure and File Structure
The port sheet system is built around two Python scripts:
/Users/cb/Documents/repos/tools/jada_port_sheet.py— the main orchestrator that reads from Google Sheets, queries Google Calendar, formats data, and generates the Excel workbook/Users/cb/Documents/repos/tools/reauth_jada_calendar.py— a credential refresh utility for maintaining valid OAuth tokens
Why Two Scripts? Google OAuth tokens expire. The calendar token (used for pulling event details) has a separate lifecycle from the Drive token. By splitting the reauth logic into its own script, we can run it as a separate Lambda function or cron job to refresh credentials independently without disrupting the main port sheet generation.
Authentication and Token Management
The system uses two separate Google Cloud service accounts / OAuth client IDs:
- Drive Client: Used to read/write Excel files in Google Drive
- Calendar Client: Used to query Google Calendar for charter event details
Credentials are stored as:
- Local development:
~/.secrets/directory (git-ignored) - Production (Lambda): Environment variable
GCAL_REFRESH_TOKENinjected via Lambda configuration
Token Refresh Flow: The reauth_jada_calendar.py script exchanges a refresh token for a short-lived access token. This token is then passed to jada_port_sheet.py`, which uses it to make calendar API calls. The refresh token itself is never transmitted; only the short-lived access token leaves the Lambda environment.
Verification Commands:
# Check if the calendar token is valid
python3 jada_port_sheet.py --dry-run
# Refresh calendar credentials if expired
python3 reauth_jada_calendar.py
# Verify the new token was written
cat ~/.secrets/gcal_token.json | grep -i access_token
Port Sheet Data Format and Google Sheets Integration
The port sheet workbook structure mirrors an existing Excel template with specific formatting requirements:
- Template Tab: Static reference sheet with column headers and formatting
- Month Tabs: One tab per month (e.g., "April 2026") containing individual charter entries
- Each entry captures: charter name, date, vessel, crew, port details, revenue
The source data comes from two Google Sheets tabs in the JADA Port Log 2026 sheet:
- Port Log: Master list of all ports and charter details
- Charter Data: Detailed information about each charter event
Why Not Store Everything in Sheets? Google Sheets is excellent for real-time data entry and collaboration, but Excel workbooks provide better formatting control, are easier to share with non-technical stakeholders, and can be archived for audit purposes. The automated pipeline reads from Sheets (the source of truth) and generates Excel (the distribution format).
Data Transformation Example
A single charter entry from the previous session:
Charter: Joseph Zurek
Date: 2026-04-15
Vessel: Primary Boat
Amount: $1,845.72
The script reads this from Google Sheets, queries Google Calendar for any related events, and formats it into the Excel "April 2026" tab using the template's cell styles and formulas.
Lambda Deployment and AWS Credentials
The port sheet generation runs in AWS Lambda with:
- Environment variable:
GCAL_REFRESH_TOKEN(the Google Calendar OAuth refresh token) - IAM role with permissions to write CloudWatch logs
- Python runtime with dependencies:
openpyxl(Excel file handling),google-auth,google-api-python-client
Token Update Process: When the calendar refresh token is rotated (either via local reauth or a manual refresh), the new token is pushed to Lambda via the AWS CLI:
aws lambda update-function-configuration \
--function-name