Realtid för bokningar¶
Mål: en ändring av en bokning på en klient ska omedelbart synas på alla andra aktiva klienter (tyst auto-uppdatering, utan toast).
Beslut: endast boknings-CRUD (BookingsController), en API-replik (in-process SignalR, ingen Redis-backplane), minimal payload + refetch på klienten.
Design¶
sequenceDiagram
participant A as Klient A
participant API as ASP.NET Core API
participant B as Klient B
A->>API: POST / PUT / DELETE /api/bookings
API->>API: EF Core SaveChangesAsync
API->>B: SignalR BookingChanged { action, id }
API-->>A: 201 / 204
B->>API: GET /api/bookings?from&to (synligt intervall)
API-->>B: 200 [bokningar]
B->>B: Hydrate + AppState.Refresh()
Händelsekontrakt¶
- Hubb:
NotificationHub(/hubs/notifications,[Authorize], JWT viaaccess_token-query — redan förberett iProgram.cs). - Händelse:
BookingChangedmed{ action: "created" | "updated" | "deleted", id: int }. - Sänds till
Clients.Allefter lyckadSaveChangesAsynciCreate/Update/Delete. Avsändaren får också händelsen — en extra refetch är ofarlig och håller logiken enhetlig.
Klientbeteende¶
SignalRService(singleton) ansluter medAccessTokenProvider = () => AuthService.Token,WithAutomaticReconnect().Home(kalenderskalet) startar anslutningen efter inloggning, prenumererar påOnBookingChangedoch gör debounced (~500 ms) tyst refetch av synligtDateFrom/DateToviaApiClient.GetBookingsAsync+State.HydrateBookings()+State.Refresh().- Ingen toast/banner. Samtidig redigering av samma bokning: last-writer-wins; formulär som sparar en raderad bokning får 404 med befintligt felmeddelande.
- Utanför intervallet eller under pågående fetch: händelsen slås ihop/ignoreras — nästa intervallbyte hämtar ändå färskt.
Avgränsningar¶
DataController-import sänder inget (CRUD-only).- Ingen Redis-backplane — vid fler än en API-replik krävs backplane för fan-out (framtida arbete).
- Ingen närvarolista eller per-rum-grupper — broadcast till alla anslutna.
Filer¶
| Område | Fil | Ändring |
|---|---|---|
| Backend | backend/Salieri.Api/Controllers/BookingsController.cs |
Injicera IHubContext<NotificationHub>, sänd BookingChanged efter create/update/delete |
| Klient | clients/Salieri.Client/Services/SignalRService.cs |
Auth-aware anslutning, typad BookingChangedEvent, idempotent start/stopp |
| Klient | clients/Salieri.Client/Pages/Home.razor(.cs) |
Injicera SignalRService/AuthService, start/stopp + debounced refetch, unsubscribe i Dispose |
Verifiering¶
- Två webbläsare mot samma API: skapa/redigera/flytta (drag)/radera i den ena — syns i den andra inom ~1 s utan omladdning.
- Utloggning stoppar socketen (ingen 401-loop); omstart av API återansluter automatiskt.
dotnet build Salieri.slnxgrön; backend-test med mockadIHubContextverifierarSendAsync("BookingChanged", …)vid POST/PUT/DELETE.