During a live open-day event, network reliability cannot be guaranteed — Wi-Fi handoffs, browser tab switches, and brief server restarts are all real scenarios. Losing the occupancy state of dozens of spaces mid-event would create chaos for tutors and coordinators. ULagos 360° addresses this with three independent storage layers that continue writing data locally regardless of connection status, plus an automatic reconciliation mechanism that merges local and server state cleanly when connectivity is restored.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Pewiz/ulagos360/llms.txt
Use this file to discover all available pages before exploring further.
Storage Layers
ULagos 360° writes space data to three separatelocalStorage locations. Each layer has a different update frequency and a different purpose.
Layer 1 — Zustand Persist Middleware (spaces-storage)
The Zustand store is configured with the persist middleware from zustand/middleware. On every state change the middleware serialises a partial snapshot — spaces, currentUser, and sessionId — and writes it under the key spaces-storage.
spaces-storage before any network request is made, so tutors see a familiar view immediately.
Layer 2 — Primary Spaces Backup (ulagos360_spaces_backup)
Every call to updateSpace or updateSpaceStatus in the Zustand store directly writes the entire spaces map to ulagos360_spaces_backup as a side-effect — synchronously, in the same set call. This means the backup is never more than one operation behind the in-memory state.
usePersistentBackup also refreshes this key every 15 seconds via setInterval.
Layer 3 — Emergency Backup (ulagos360_emergency_backup)
usePersistentBackup writes a richer snapshot every 15 seconds that wraps the spaces map with a human-readable timestamp and a version tag:
visibilitychange) or when the page is about to unload (beforeunload), capturing any last-second changes before a potential crash.
What Happens on Disconnect
When the Socket.IO connection drops, no space data is lost:- The Zustand store remains fully populated in memory and in
spaces-storage. - Tutors can continue reading the last-known state and even make local updates (the store will write them to
localStorageand queue them). usePersistentBackupkeeps its 15-second interval running; both backup keys continue to be refreshed.- The connection indicator in the header changes to show an offline state, alerting tutors that changes are not yet propagating to peers.
What Happens on Reconnect
Socket.IO will attempt to reconnect automatically (up to 5 times). Once the connection is re-established,useSocketConnection triggers the following sequence:
Re-register the tutor
register_user is emitted with the saved sessionId and user object recovered from localStorage.Request full state from server
get_all_spaces is emitted immediately. The server responds with spaces_state (or one of its aliases), which the client applies to the Zustand store.Upload local state if server is slow
If the server has not responded within ~5 seconds,
sync_spaces is emitted with the entire local spaces map, the userId, sessionId, and a current timestamp. This ensures the server has the freshest data even if it restarted during the outage.Manual Recovery
If spaces appear empty after a reconnect (for example after a hard reload or a server-side state reset), tutors can manually restore data from the local backup without refreshing the page. In the header, click the ↺ (RotateCcw) button. This callsrecoverFromBackup() from usePersistentBackup, which attempts restoration in priority order:
- Parse
ulagos360_spaces_backup— if it contains a non-empty spaces object, return it immediately. - If the primary backup is empty or corrupt, fall back to
ulagos360_emergency_backupand extract thespacesfield from the timestamped snapshot. - If both are empty, return
nulland the UI will prompt the user to contact support.
localStorage Keys Reference
| Key | Contents | When Updated |
|---|---|---|
spaces-storage | Full Zustand state snapshot: spaces map, currentUser object, and sessionId | Every state change via Zustand persist middleware |
ulagos360_spaces_backup | Plain spaces object (all space records) | On every updateSpace / updateSpaceStatus call, and every 15 s by usePersistentBackup |
ulagos360_emergency_backup | { spaces, timestamp, version: "2.0" } | Every 15 s, plus immediately on tab hide and page unload |
ulagos360_current_user | Current tutor object { id, name, … } | On login or when the server confirms user registration |
ulagos360_session_id | Session identifier string (session_<timestamp>_<random>) | On first app load; persists for the lifetime of the session |
sessionId | Legacy session identifier (same value as ulagos360_session_id) | Written by useSocketConnection on each successful connection |
currentUser | Legacy tutor object copy | Written by useSocketConnection on register and on each user event |
lastStateSync | Epoch millisecond string of the last full-state response from the server | After each successful spaceStateEvents handler run |
logout_in_progress | Presence flag (no value needed) set before socket disconnect | Set by logout flow; cleared on next successful connect event |
All persistent state keys are cleared during a deliberate logout.
spacesStore.logout removes ulagos360_current_user, ulagos360_session_id, spaces-storage, ulagos360_spaces_backup, ulagos360_emergency_backup, and lastStateSync. useSocketConnection.logout additionally removes sessionId. The result is a fresh tutor identification screen on the next page load with no residual data.