Skip to main content

Broadcasting an Alert

Some events can't wait for someone to happen to glance at the right camera: a spreading fire, an evacuation boundary, a hazard other agencies need to know about now. The Alerts feature lets an authorized operator draw that event on the map and push it — as a marker every user can see, and as email/SMS/phone notifications to everyone whose subscription matches.

The form

AlertMessage (in components/molecules/Notifications/) collects the alert: a location picked interactively on the map (latitude, longitude, and a radius up to 10 miles), an urgency level, a message, the recipients (specific agencies, specific users, or broadcast), and optionally a snapshot of the map for spatial context.

Validation is react-hook-form + a Zod schema, and the schema is the contract worth reading:

const AlertMessageSchema = z.object({
message: z.string(),
latitude: z.number(),
longitude: z.number(),
radiusInMiles: z.number().min(0).max(10),
recipientAgencyIds: z.array(z.number()).nullable(),
recipientEntraUserIds: z.array(z.string()).nullable(),
imageUrl: z.string().nullable(),
cameraId: z.string(),
urgencyLevel: z.number().min(0).max(4), // 0=None, 1=Low, 2=Medium, 4=High
mapImage: z.instanceof(Blob).nullable(),
});

Note urgencyLevel — those aren't sequential values. They're bitmask levels, and the subscription side depends on that; the next lesson explains the scheme.

The journey after submit

Because the payload can carry a map-image Blob, this route breaks the usual JSON pattern: the form posts multipart FormData to /api/alerts/alert-create, where the BFF parses the multipart body, re-validates, and forwards fields plus image to the backend.

From there, the backend takes over — this is the hand-off boundary where frontend work ends:

  1. A marker is created on the ESRI map, visible to users with map access (clicking it goes through the AGOL click pipeline)
  2. The alert's location, radius, urgency, and timing are matched against user subscriptions
  3. Notifications go out on each recipient's chosen channels

Frontend feedback is standard: inline Zod errors before submit, success/error surfaced in the UI after.

Wrapping up

One form, one Zod contract, one multipart hop through the BFF — then the backend fans it out to the map and to every matching subscriber. Which subscribers match is the other half of the story: Notification Settings.