Making the JADA Maintenance Dashboard Task Card Clickable: S3 + CloudFront Cache Invalidation Strategy
What Was Done
The JADA Maintenance Hub dashboard displays a "Total Tasks" summary card in the top-level overview. Users needed a direct interaction path from that card to the detailed Tasks view. The solution involved:
- Locating the maintenance hub's
index.htmlfile in the S3 bucket - Identifying the tab navigation architecture and the Tasks data rendering logic
- Making the Total Tasks card clickable with proper styling and
onclickevent binding - Invalidating the CloudFront distribution cache to serve the updated file immediately
Technical Details: Finding and Modifying the Asset
The maintenance hub is a single-page application (SPA) served as a static asset from S3. The file structure is:
s3://jada-maintenance-hub/index.html
The HTML uses tab-based navigation controlled by a switchTab() function in the embedded JavaScript. The task rendering logic was found within a tab element with data-tab="systems". The Total Tasks card was originally a passive div with class info-card:
<div class="info-card">
<div class="info-card-title">Total Tasks</div>
<div class="info-card-value">82</div>
</div>
Why this needed to change: Static cards provide no affordance for user interaction. Making it clickable reduces friction — users can navigate from summary to detail in a single gesture rather than hunting for a tab selector.
Implementation: DOM Changes and Event Binding
The card was wrapped in a clickable container with semantic styling:
<div class="info-card info-card-link" onclick="switchTab('systems')">
<div class="info-card-title">Total Tasks</div>
<div class="info-card-value">82</div>
</div>
A new CSS class info-card-link was added to provide visual feedback:
.info-card-link {
cursor: pointer;
transition: background-color 0.2s ease, transform 0.15s ease;
}
.info-card-link:hover {
background-color: rgba(52, 152, 219, 0.08);
transform: translateY(-2px);
}
.info-card-link:active {
transform: translateY(0);
}
Design rationale: The hover state uses a subtle color shift and vertical translate to indicate interactivity without overwhelming the dashboard aesthetic. The active state removes the lift to provide tactile feedback. Transitions are short (150–200ms) to feel responsive without appearing sluggish.
The switchTab('systems') call reuses the existing tab navigation logic, which:
- Hides all tab panels with
display: none - Shows only the target panel with
display: block - Updates the active tab indicator in the navigation UI
This approach avoids code duplication and maintains consistency with the rest of the navigation system.
Infrastructure: S3 + CloudFront Deployment Pipeline
S3 Bucket Configuration:
Bucket Name: jada-maintenance-hub
Region: us-west-2
Access: Private (CloudFront OAI only)
Versioning: Enabled
Object Path: /index.html
The bucket is configured with a block-public-access policy — all traffic flows through CloudFront, never directly from S3. This enforces cache coherency and security.
CloudFront Distribution:
Domain: maintenance.jada-internal.tech
Origin: jada-maintenance-hub.s3.us-west-2.amazonaws.com
Origin Access Identity (OAI): jada-maintenance-hub-oai
Cache Behavior (index.html):
- TTL: 3600 seconds (1 hour)
- Compress: Yes (Gzip)
- Query String Forwarding: None
Why CloudFront: Distributes content to edge locations globally, reducing latency for remote crew members accessing the dashboard from different harbors. The 1-hour TTL balances freshness against cache hit rates — dashboard updates don't need sub-minute propagation, but we avoid cache staleness during a maintenance session.
Cache Invalidation: The Critical Step
After uploading the modified index.html to S3, the CloudFront cache needed invalidation to force edge servers to fetch the new version immediately:
aws cloudfront create-invalidation \
--distribution-id E1A2B3C4D5E6F7 \
--paths "/index.html" \
--region us-west-2
Why this matters: Without invalidation, users would see the old cached version for up to 3600 seconds, defeating the purpose of the update. The invalidation request propagates to all edge locations within 60–120 seconds. The response includes an invalidation ID (e.g., ABCDEFG1234567) that can be polled to confirm completion.
Cost consideration: CloudFront charges $0.005 per invalidation path after the first 3000/month. Batching multiple changes into a single deployment reduces invalidation overhead. For a single-file update, the cost is negligible, but this pattern scales poorly for high-frequency deployments.
Testing and Validation
After the cache invalidation completed, the following was verified:
- DOM inspection: The card element has
onclick="switchTab('systems')"and theinfo-card-linkclass is applied - CSS application: Hovering over the card shows the background color shift and vertical lift
- Click behavior: Clicking the card switches the active tab to Systems and the task table becomes visible
- Cache headers: Response headers include
Cache-Control: max-age=3600andVia: cloudfront, confirming edge delivery
Key Decisions and Trade-offs
Inline onclick vs. Event Listeners: The inline onclick was chosen over JavaScript event listeners because the page is a lightweight SPA with no build tooling. Inline handlers are simpler for static assets and avoid the need to defer script execution.
CSS class for styling: Rather than inline styles, a separate .info-card-link class allows the style to be updated globally if multiple cards become clickable in the future. It also keeps presentation logic in the stylesheet, not the markup.
1-hour TTL: A longer TTL (e.g., 24 hours) would reduce origin load, but dashboard data and UI changes need faster propagation during active maintenance sessions. One hour is a practical balance.
What's Next
Future improvements could include: