Skip to main content

The Query Surface

Movement, auth, and real-time are the parts with moving pieces. But most of the API is quieter and more numerous: "give me the cameras I can see," "the images for this camera and time range," "my notifications." These read endpoints are the bulk of what the frontend calls, and they all share one shape.

The one idea to hold on to​

Every read endpoint is a thin CQRS query: controller → MediatR query → Infrastructure repo, returning a frontend-shaped DTO — not a raw storage entity. The controller decides the shape and the caller's scope; the handler fetches and maps. Because the mapping happens here, the frontend never couples to Cosmos or SQL models — it depends on the API's DTOs, and the storage schema can change underneath without breaking the app.

The read domains, each a Queries folder in the Application layer (reach for the source for the exact query list rather than a catalog here):

ControllerAnswers
Cameras · CameraFiltersWhich cameras this user can see, and how they're filtered/grouped
Images · VideoLibraryFrames and clips for a camera and time range
Alerts · NotificationsActive alerts and the user's notifications
ActivityLogRecent movement/activity per camera
AiDetectionCondor detections surfaced to the operator
SharedViews · User · FeatureFlagsSaved map views, user preferences, and flag state
Gotcha: scope is enforced per query, not globally

"Which cameras" is a user-scoped question — the camera queries filter to what the caller is allowed to see (the RBAC allow-list from the shared data layer). Don't assume a camera id in a URL is automatically authorized just because the request has a valid token; the scoping is in the query, so a new read endpoint has to apply the same filter or it will over-share. When adding a query, copy a scoped sibling.

Wrapping up​

The query surface is the API's calm majority: many thin CQRS reads (and some commands) that map shared storage into frontend-shaped DTOs, keeping the app decoupled from the schema — with per-query scoping as the thing you must not forget when extending it. Together with movement, auth, and real-time, that's the whole backend-for-frontend.

Back to the overview: The Frontend's Backend.