Hybrid, PWA, Offline & Device-Aware Applications
The EnterpriseOps Command Center grows a Field Technician mode
(UI.FieldTechnicianPage) with a device-aware layout, an offline work-order cache in a local store, a
local completion queue of OfflineCommands with an explicit SyncState, a reconnect sync simulation that
replays the queue through the same server service the online screen uses, and a SyncConflictPanel that
shows both versions when the dispatcher changed a work order while the technician was offline.
Everything is in-memory. Nothing is deployed, no database, no network, no cloud account, no device.
Run it
cd "LearnWisej-Samples/Enterprise Wisej.NET Course\Module 13\EnterpriseOps"
dotnet run -f net10.0 --urls http://localhost:5213
Then open http://localhost:5213. (Visual Studio: open EnterpriseOps.slnx, press F5 — the port is in
Properties/launchSettings.json.) Requirements: .NET 10 SDK and the Wisej-4 4.1.0 NuGet package.
The screen
EnterpriseOps — Field Technician mode
┌ device frame (380 / 620 / 860 px, from the detected device) ───────────┐
│ Field mode [Go offline] [ ONLINE ] │
│ WORK ORDERS — LOCAL CACHE (SQLITE) · 12 ROWS · DOWNLOADED 09:14 │
│ │ WO-1037 │ Valve yard — replace relief valve │ … │ Assigned │ … │ │
│ │ WO-1038 │ Substation B — inspect breaker │ … │ Assigned │ … │ │
│ COMPLETION NOTES [ seal replaced, torqued to spec ] │
│ [ Complete… ] [ Scan ] ✓ ASSET-Pump-88121 matches … │
│ COMPLETION QUEUE — 2 PENDING │
│ │ WO-1038 │ Completed 11:48 — breaker OK │ PendingSync │ │
│ ┌ Sync conflict — WO-1037 (appears on conflict) ┐ │
│ ▓▓▓▓░░ Offline — 2 completion(s) queued locally · cache: 12 work orders│
└─────────────────────────────────────────────────────────────────────────┘
The frame width, touch-target height and the Site / v columns follow Application.Browser
(phone 380 px / 44 px, tablet 620 px / 40 px, desktop 860 px / 34 px). To see the phone layout, open the
app on a phone or in the browser's device emulation and reload.
What to click
| Control | Path | What you should see |
|---|---|---|
| Complete… (online) | success | Green toast "WO-1041 completed (v3)."; the grid's Server status turns Completed; nothing is queued. |
| Complete… (offline) | queued | Toast "No signal — WO-1038 is queued locally…". Server status still says Assigned, On this device says Completed · pending sync, and an amber PendingSync card appears in the queue. |
| Complete… (empty notes) | validation | Rejected before anything is queued: "Enter what you did before completing the work order." |
| Scan | device capability | Online, the scanned tag is validated on the server (the simulated tags rotate: one matches the site, others are refused). Offline, it is recorded for validation at sync. The tag is appended to the notes. |
| Go offline / Go online | reconnect sync | The pill flips ONLINE ⇄ OFFLINE. Going online with a non-empty queue replays it on a background task (Application.StartTask + Application.Update): one command per 700 ms, the progress bar advances, cards turn green Synced. While the device is offline the dispatcher (ana.ops) cancels WO-1037 on the server, so a completion of WO-1037 queued offline comes back as a conflict. |
| Keep server — attach my notes (conflict panel) | resolution | WO-1037 stays Cancelled, the technician's notes are attached and audited, the card turns grey Rejected · kept server — notes preserved, and any commands behind it resume. |
| Apply my completion… (conflict panel) | failure: product rule | ben.tech is a Technician: the server refuses with the workorder.override rule, audits the refusal, and the panel stays open. |
The demo (reproduces the video)
- Complete… on
WO-1041while online (success). - Go offline.
- Select
WO-1038, type notes, Complete… (queued). - Select
WO-1037, typerelief valve replaced, torqued to spec, Complete… (queued). - Go online:
WO-1038→Synced, thenWO-1037→ Conflict, both versions on screen. - Apply my completion…: refused, audited, panel stays open.
- Keep server — attach my notes: resolved, nothing lost.
Service, queue and sync decisions are written to the server log (System.Diagnostics.Trace, e.g. the
Visual Studio Output window) with a layer prefix: Service:, Data:, Security:, Device:, Job:.
Where things live
EnterpriseOps/
├─ UI/ FieldTechnicianPage · SyncConflictPanel · OfflineCommandRow (one queue card)
├─ Hybrid/ HybridOfflinePatterns · DeviceServices · LocalStore · OfflineCommandQueue · SyncWorkflow
├─ Services/ WorkOrderService (the only code that changes a work order) · Commands · SessionContext · ActivityTrace (server log)
├─ Security/ PermissionService (server grants + CachedPermissionSet) · AuditLog (device time + server time)
├─ Domain/ WorkOrder (Version = concurrency token)
├─ Data/ FakeWorkOrderRepository · SeedData (48 work orders, 12 in ben.tech's field cache)
└─ docs/ the five deliverables (+ 2 SVGs, + the PWA shell)
Notes
Application.Update(this, …)(two-argument form) pushes the replay steps fromApplication.StartTask.- The queue control is a
DataRepeaternamedrepQueue; this sample renders the same cards withOfflineCommandRowuser controls in aFlowLayoutPanel(flpQueue). Swapping in aDataRepeaterchanges onlyRenderQueue(). - The file tree shows seven projects; this course keeps one project with folder-per-layer
namespaces so the sample runs with a single
dotnet run. LocalStore.csis the in-memory stand-in for theLocalStore.Sqlite.cs.