AWS Builder Center
Designing a Safety Alert That Doesn't Lie with Colour

Designing a Safety Alert That Doesn't Lie with Colour

A red square means little when colour is the only signal. For ShramShield, I designed a heat-safety dashboard around explicit instructions, accessible status indicators, honest error states, and a run timeline that makes waiting and escalation visible. Here's what I learned building a safety-focused frontend against a serverless AWS API.

Designing a Safety Alert That Doesn't Lie with Colour

I built the dashboard for ShramShield, a heat-safety screening system designed to help outdoor worksite supervisors understand weather-based heat risk and work-rest guidance.
My first instinct was to make the interface visual: colour-coded heat levels, cards, charts, and a timeline of hourly conditions.
But I kept coming back to one question:
What happens when someone cannot distinguish the colours, the data is missing, or the dashboard quietly shows an old result?
In a safety-focused interface, a beautiful screen is not enough. The interface has to communicate clearly, including when something goes wrong.

Colour Is Not Information

A colour-coded dashboard looks intuitive until colour becomes the only way to understand a status.
Red and green can be difficult to distinguish for some users. Even without a colour-vision deficiency, a user might be viewing a screen in bright sunlight, on a low-quality display, or while working under time pressure.
So I used a simple design principle for ShramShield:
Every important status should communicate through its label and meaning, not colour alone.
Instead of showing just a red cell, the interface should also show the risk level and the corresponding instruction.
For example:
Plain text
10 AM | VERY HIGH | 31°C
| Work-rest guidance
The actual work-rest recommendation comes from the project's screening logic and applicable limits; it should not be guessed from the colour of a card.
This principle influenced how I thought about heat levels, selected states, buttons, alerts, and the hourly timeline.
A visual indicator should reinforce information, not replace it.

Building the Frontend Before the Backend Was Ready

One challenge was developing the interface while the backend and AWS workflow were being built by another team member.
Waiting for every endpoint to be ready would have slowed development. Inventing arbitrary response structures, on the other hand, would have created unnecessary integration problems later.
Our solution was to work against an agreed API contract and committed fixtures.
The frontend supports mock and live modes through a central configuration:
Plain text
const LIVE_MODE =
import.meta.env.VITE_USE_MOCK === 'false' &&
Boolean(API_BASE);
Mock mode lets the interface be developed and tested without sending real notifications. Live mode uses the configured API and should display errors when a request fails rather than silently pretending that mock data came from AWS.
This separation was useful because the interface could evolve while the backend work continued independently.
It also exposed an important lesson: every API method needs an explicit implementation for the mode in which it is used.
A page can look perfectly complete in mock mode but fail when the live client does not support the same operation. The Backtest page exposed exactly this kind of gap during integration.
That reminded me to test not just the visual layout, but also the boundary between frontend components and the API.

Designing an Honest Run Timeline

The run timeline became one of the most important parts of the interface.
ShramShield's notification workflow can build a heat plan, prepare a Hindi voice message, send a Telegram notification, wait for acknowledgement, and escalate to a backup contact if no response arrives before the configured timeout.
Displaying a single “Alert sent” message would hide most of what matters.
The run page therefore presents the workflow as a sequence of events, with a status indicator and an acknowledgement countdown.
Three design decisions mattered most.

1. Stop polling when the run is finished

The frontend polls the run-status endpoint while the workflow is active. It should stop polling when the run reaches a final status, pause while the browser tab is hidden, and clean up its timers when the user leaves the page.
These details might sound minor, but they prevent needless requests and avoid background activity continuing after the information is no longer changing.

2. Translate technical events into understandable language

The backend may return event codes such as  notified_primary ,  escalated , or  telegram_failed .
Those codes are useful to developers, but they are not ideal language for a worksite supervisor.
The dashboard translates them into readable descriptions such as “Supervisor notified,” “No answer: escalating to backup,” and “Telegram delivery failed.”
The goal is to make the event history understandable without requiring users to know the implementation.

3. Make the countdown reflect the actual deadline

The countdown should be derived from the server-provided acknowledgement deadline, not just start a timer when the user clicks a button.
That distinction matters whenever a page is refreshed or reopened. The interface should reflect the workflow's actual deadline instead of displaying a countdown that looks plausible but is no longer accurate.

Empty States Are a Safety Feature

A missing value or failed request should never be disguised as a healthy result.
For example, an unavailable weather value should be identified as  NO DATA , rather than shown as a neutral-looking cell that users might interpret as low risk.
The voice player revealed a similar issue. ShramShield serves its Hindi audio through a temporary S3 pre-signed URL. When that URL expires, the audio player cannot load the file.
The frontend now shows an explicit expired-link message and a link to open the audio rather than leaving the user with an unexplained, silent player.
This improves the interface's honesty, although a complete fix also requires the backend to generate fresh URLs for older run records.
That is the broader lesson: a clear error message improves the user experience, but it does not replace fixing the underlying problem.

Accessibility Is Part of the Interface

Accessibility is not a decorative feature to add after the design is complete.
For a dashboard that communicates important status information, I focused on understandable labels, semantic headings, visible focus states, keyboard-accessible controls, and status updates that assistive technologies can identify.
The interface should remain understandable if colour is unavailable, and important status changes should not depend exclusively on visual animation.
I also treated the loading, error, empty, waiting, and completed states as part of the actual design—not as edge cases to ignore until later.
These decisions make the interface more predictable for everyone, not only for users with specific accessibility needs.

What I Learned

Building ShramShield's frontend taught me three important lessons.
A design must communicate meaning. Colour, charts, and cards are helpful only when users can understand the information they represent.
Mock mode is a development tool, not proof of integration. It makes isolated testing easier, but live API behaviour must still be verified against the deployed backend.
Honest failure states build trust. Showing stale data, an expired voice link, or a failed request as if everything were working would make the dashboard less reliable, no matter how polished it looked.
The frontend's mock workflow tests and production build passed. However, the complete live Run Now flow still requires end-to-end verification against the deployed API. Keeping that distinction clear is part of building a trustworthy interface.

Conclusion

ShramShield is a reminder that frontend engineering is more than arranging components on a screen.
For a heat-safety dashboard, the interface has to communicate risk clearly, show what the notification workflow is doing, and admit when information or an operation is unavailable.
My biggest takeaway is simple:
In a safety-focused interface, the best design is not the one that looks the most urgent. It is the one that helps people understand what is happening and what information they can actually rely on.
I'd love to hear how other developers approach accessible status indicators, mock-first development, and error states in interfaces where clarity matters.
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article