You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -55,18 +81,37 @@ dotnet user-secrets set "ScanEventApi:BaseUrl" "https://your-api-host" --project
55
81
dotnet run --project src/ScanEventWorker/ScanEventWorker.csproj
56
82
```
57
83
58
-
---
59
-
60
84
## Assumptions
61
85
62
86
1.~~Events are returned ordered by `EventId` ascending~~
63
87
2.~~`EventId` is monotonically increasing — querying `FromEventId=X` reliably returns all events with ID ≥ X~~
64
-
3. The API returns an empty `ScanEvents` array when no more events exist (end-of-feed signal)
65
-
4. Only one worker instance runs at a time (no distributed locking required)
88
+
3.~~The API returns an empty `ScanEvents` array when no more events exist (end-of-feed signal)~~
89
+
- guarded: `ApiPollerWorker` checks `Count == 0` and backs off
90
+
4.~~Only one worker instance runs at a time~~
91
+
- enforced: startup `Mutex` in `Program.cs` aborts a second instance
66
92
5.`RunId` comes from the nested `User.RunId` field in the JSON response
93
+
- guarded: `null` coalesces to `string.Empty`
67
94
6.`StatusCode` may be an empty string
68
-
7.`PickedUpAtUtc` and `DeliveredAtUtc` are set on the **first** occurrence of their respective event types and are never overwritten by later events of the same type
69
-
8. Unknown `Type` values are stored as-is in `ParcelSummary` without setting pickup/delivery timestamps
95
+
- guarded: `null` coalesces to `string.Empty`
96
+
7.~~`PickedUpAtUtc` and `DeliveredAtUtc` are set on the **first** occurrence of their respective event types and are never overwritten~~
97
+
- enforced: `??=` in `ParcelSummary` + `IS NULL` in SQL MERGE
98
+
8.~~Unknown `Type` values are stored as-is in `ParcelSummary` without setting pickup/delivery timestamps~~
99
+
- enforced: `switch` default + SQL `CASE`
100
+
9.`CreatedDateTimeUtc` is the timestamp recorded as `PickedUpAtUtc`/`DeliveredAtUtc`
101
+
- the spec sample contains a `CreatedDateTimeUtc` field on each event
102
+
- no separate pickup/delivery timestamp field is defined
103
+
10. First PICKUP/DELIVERY occurrence sets the timestamp permanently
104
+
- the spec is silent on correction or reversal events
105
+
- enforced: `??=` in `ParcelSummary` + `IS NULL` guard in SQL MERGE
106
+
11.`Device` fields (`DeviceId`, `DeviceType`) and `User.UserId`/`User.CarrierId` from the API response are not persisted
107
+
- the spec only defines `ParcelSummary` columns
108
+
- extra fields are silently ignored
109
+
12.`STATUS` events update the most-recent-event columns (`LatestType`, `LatestStatusCode`, etc.) but do not affect `PickedUpAtUtc`/`DeliveredAtUtc`
110
+
13. Polling uses `FromEventId=LastEventId` (inclusive) rather than `LastEventId+1`
111
+
- the last processed event is re-fetched on every cycle to avoid missing events if IDs have gaps
112
+
- the idempotent MERGE absorbs the duplicate without side effects
113
+
14. The event feed starts at `EventId=1`
114
+
-`ProcessingState` is seeded with `LastEventId=1` on first run d
0 commit comments