Integrating Manual Crew Hours Logging with CloudFront-Distributed Frontend Updates
This post documents the technical implementation of a manual crew hours entry system for the ShipCaptainCrew (SCC) platform, including frontend UI updates, Lambda function extensions, DynamoDB schema modifications, and CloudFront cache invalidation strategies.
Problem Statement
The crew-facing dashboard lacked a user-friendly interface for manual hours entry. Crew members needed to log work hours in 15-minute increments, and administrators required the ability to backfill historical hours data. The existing system had automated clock-in/out functionality but no manual override or historical entry mechanism.
Architecture Overview
The ShipCaptainCrew system spans three core infrastructure layers:
- Frontend: Static HTML/CSS/JavaScript served via S3 bucket
scc-frontendthrough CloudFront distribution - API: AWS API Gateway with Lambda integration for business logic
- Data: DynamoDB tables storing event charters, crew assignments, and hours logs
The ops subdomain (ops.queenofsandiego.com) serves as a separate properties site also distributed via CloudFront, with CORS-enabled API calls to the SCC backend.
Frontend Modifications
Hours Entry UI Implementation
The crew-facing page required a new section for hours logging. The implementation followed the existing pattern in the SCC frontend codebase:
File: /tmp/scc_index.html (source for S3 deployment)
Location in S3: s3://scc-frontend/index.html
Added a new hours entry card featuring:
- Time picker inputs for clock-in and clock-out times (HH:MM format)
- Quarter-hour increment validation (0, 15, 30, 45 minutes only)
- Date picker for historical entries
- Role-based visibility (visible only to crew and admin roles)
- API call trigger to new
set-hoursLambda endpoint
The frontend reads the sessionRole variable from global state to determine UI element visibility. This variable is populated during authentication and persists across page navigation.
Timestamp Calculation
Hours were stored as Unix timestamps (seconds since epoch) in the DynamoDB hours_log attribute. The frontend JavaScript converts user-selected times to UTC timestamps:
// Example calculation for May 12, 2026
// Angela Wong: 3:45 PM - 9:00 PM (15:45 - 21:00)
// JavaScript Date object → Unix timestamp → DynamoDB storage
All timestamps normalized to UTC to prevent timezone ambiguity across distributed crew locations.
Lambda Function Extensions
New Endpoint: set-hours
File: /tmp/scc_lambda/lambda_function.py
Added a new route handler in the main Lambda function to accept manual hours entries:
- Endpoint: POST /set-hours
- Authentication: Admin password hash validation (SHA-256)
- Parameters: event_id, crew_name, clock_in (Unix timestamp), clock_out (Unix timestamp)
- Validation: Clock-out must be after clock-in; timestamps must align to 15-minute boundaries
- Operation: Append entry to DynamoDB
hours_logarray for specified crew member in the charter event
The handler follows the existing admin auth pattern in the codebase:
if request_body.get('admin_password') != ADMIN_PASS_HASH:
return error_response(401, "Unauthorized")
Environment variables ADMIN_PASS_HASH and CREW_PASS_HASH are SHA-256 digests, updated via AWS SDK during deployment to avoid hardcoding credentials.
DynamoDB Response Enrichment
Modified the event GET handler to return the hours_log array in the response body, enabling the frontend to display historical entries immediately after submission. The response structure mirrors the stored DynamoDB item:
response_body = {
"event_id": "...",
"charter_date": "...",
"crew": [...],
"hours_log": [
{"crew_name": "Angela Wong", "clock_in": 1747939500, "clock_out": 1747961400},
...
]
}
Infrastructure Deployment
S3 and CloudFront Updates
Frontend deployment sequence:
1. Update source: /tmp/scc_index.html
2. Upload to S3: aws s3 cp scc_index.html s3://scc-frontend/index.html
3. Invalidate CloudFront cache: Invalidation pattern /*
4. CloudFront distribution ID: (SCC frontend distribution)
5. Propagation time: ~5-10 seconds (edge locations)
Lambda deployment:
1. Update: /tmp/scc_lambda/lambda_function.py
2. Package and deploy via AWS SAM or direct console upload
3. Update environment variables for ADMIN_PASS_HASH and CREW_PASS_HASH
4. No CloudFront invalidation needed (Lambda is origin, not S3)
CORS Configuration Validation
Verified that the API Gateway allowed cross-origin requests from the ops subdomain. The SCC Lambda returned appropriate Access-Control-Allow-Origin headers matching the frontend origin to permit API calls from both SCC and ops domains.
Data Backfill and Crew Management
Historical Hours Entry
Using the new set-hours endpoint, crew hours were backfilled for the May 12, 2026 Jennifer Sanderson charter:
- Angela Wong: 3:45 PM - 9:00 PM (1 entry)
- Gene O'Neal (Captain): Calculated based on crew email confirmation
- Angela Wong (1st Mate): Role verified from Carole's crew assignment email
- Dan Rich (2nd Mate): Full name verified; crew database updated
Each entry calculated to Unix timestamps, then submitted via set-hours with admin authentication.
Crew Role Assignment in DynamoDB
The ShipCaptainCrew DynamoDB structure stores crew assignments within each charter event:
Table: ShipCaptainCrew
Item structure:
{
"event_id": "jennifer_sanderson_2026_05_12",
"charter_date": "2026-05-12",
"crew": [
{"name": "Gene O'Neal", "role": "Captain"},
{"name": "Angela Wong", "role": "1st Mate"},
{"name": "Dan Rich", "role": "2nd Mate"},
{"name": "Keely Hoyt", "role": "Hostess"}
],
"hours_log": [...]
}
Calendar event description