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
**Scope:** Dual-publish the entire OS4CSAPI publisher fleet to the connected-systems-go server
6
6
7
7
---
@@ -10,7 +10,7 @@
10
10
11
11
OS4CSAPI has deployed a second Connected Systems API server — [connected-systems-go](https://github.com/OS4CSAPI/connected-systems-go) — alongside the existing OSH SensorHub. This report documents the integration effort: server architecture, behavioral differences discovered during live testing, workarounds applied, publishers migrated to date, and the plan to complete the remaining fleet.
12
12
13
-
**Current state:**2 of 10 publishers dual-publishing. 6 GitHub issues filed against the Go server.
13
+
**Final state:**10 of 10 publishers dual-publishing on the Go server. 37 systems, 58 datastreams, 11 procedures, 58 deployments bootstrapped. All services running as systemd units with observations flowing. 6 GitHub issues filed against the Go server, plus 4 additional behavioral differences discovered during fleet-wide migration.
14
14
15
15
---
16
16
@@ -129,7 +129,39 @@ During live integration testing, we identified 6 differences between connected-s
129
129
-**Workaround (Explorer):**`extractSystemId()` helper with `system@link.href` fallback. Pushed as commit `2f0869a`.
130
130
-**Workaround (Library):**`parseBaseStream()` in `part2.ts` checks `system@link.href` → `system@id` chain. Filed as [ogc-client-CSAPI_2#166](https://github.com/OS4CSAPI/ogc-client-CSAPI_2/issues/166).
131
131
132
-
### 3.3 Other Go Server Characteristics
132
+
### 3.3 Additional Behavioral Differences (Discovered During Fleet Migration)
133
+
134
+
These were discovered during the full fleet migration and are not yet filed as issues.
135
+
136
+
#### Unique constraint on datastream `unique_identifier` (global scope)
137
+
138
+
-**Severity:** P2-Major
139
+
-**Problem:** PostgreSQL `idx_datastreams_unique_identifier` enforces global uniqueness across ALL datastreams, not just within a system. Multi-station publishers initially shared one UID template (e.g., `urn:os4csapi:datastream:nws:nwsSurfaceObs:v1`) for all stations — the second station's datastream creation failed.
140
+
-**Workaround:** All multi-station publishers now generate per-station UIDs: `urn:os4csapi:datastream:nws:{station_id}:nwsSurfaceObs:v1`.
-**Problem:**`GET /systems?uid=urn:os4csapi:...` returns ALL systems (unfiltered) instead of the matching one. Combined with the default pagination limit of 10, `find_by_uid()` missed resources beyond the first page.
147
+
-**Workaround:**`find_by_uid()` now appends `&limit=1000` to all queries and matches client-side.
148
+
-**File changed:**`bootstrap_helpers.py`.
149
+
150
+
#### `/deployments` only returns top-level deployments
151
+
152
+
-**Severity:** P3-Minor
153
+
-**Problem:**`GET /deployments` does not include sub-deployments in results. Sub-deployments are only accessible via `GET /deployments/{parent_id}/subdeployments`.
154
+
-**Workaround:**`ensure_deployment()` now searches `deployments/{parent_id}/subdeployments` when `parent_id` is provided.
155
+
-**File changed:**`bootstrap_helpers.py`.
156
+
157
+
#### Strict result schema validation (timestamp required)
158
+
159
+
-**Severity:** P3-Minor (extends Issue #5)
160
+
-**Problem:** Go server validates that observation results contain ALL fields defined in the datastream schema, including `timestamp`. Publishers were popping `timestamp` from results (SensorHub auto-fills it from `phenomenonTime`), causing `result.timestamp is required by datastream schema` errors.
161
+
-**Workaround:** All publishers now re-add `timestamp` from `phenomenonTime` when targeting Go server.
162
+
-**Files changed:** All 8 publisher files.
163
+
164
+
### 3.4 Full Behavioral Comparison
133
165
134
166
| Behavior | SensorHub | connected-systems-go |
135
167
|---|---|---|
@@ -138,19 +170,24 @@ During live integration testing, we identified 6 differences between connected-s
**`find_by_uid()`** — Updated to check both `items` and `features` keys in collection responses, since the Go server wraps geo-resources in GeoJSON `features` arrays:
149
-
150
-
```python
151
-
# Support both GeoJSON (features) and flat JSON (items) collections
152
-
items = result.get("items", []) or result.get("features", [])
153
-
```
185
+
| Change | Detail | Commit |
186
+
|---|---|---|
187
+
| GeoJSON support |`find_by_uid()` checks both `items` and `features` keys |`e022ef2`|
188
+
|`OSH_BASE_URL`|`get_config()` reads `OSH_BASE_URL` env var as server URL fallback |`906ae33`|
189
+
| Pagination fix |`find_by_uid()` appends `&limit=1000` to all queries |`92f584b`|
190
+
| Subdeployment search |`ensure_deployment()` searches `deployments/{parent_id}/subdeployments` when `parent_id` set |`3a02268`|
-**UAS Simulator** — FastAPI service, not a publisher in the same sense; separate integration path.
293
422
-**Localizer** — Depends on UAS simulator data; separate integration path.
294
423
424
+
### 7.1 VM Deployment Layout
425
+
426
+
Each Go publisher has its own directory under `/home/ubuntu/`:
427
+
428
+
```
429
+
/home/ubuntu/nws-publisher-go/
430
+
/home/ubuntu/ndbc-publisher-go/ # Also serves ndbc-buoycam-publisher-go
431
+
/home/ubuntu/coops-publisher-go/
432
+
/home/ubuntu/aviation-wx-publisher-go/
433
+
/home/ubuntu/usgs-water-publisher-go/
434
+
/home/ubuntu/usgs-nims-publisher-go/
435
+
/home/ubuntu/iss-publisher-go/
436
+
/home/ubuntu/usgs-eq-publisher/ # Shared dir (no -go suffix)
437
+
/home/ubuntu/OSHConnect-Python/ # OpenSky uses main repo clone
438
+
```
439
+
440
+
Each directory contains a copy of the relevant `publishers/` subtree plus `bootstrap_helpers.py`. Staging repo clone at `/tmp/OSHConnect-Python` for updates.
441
+
295
442
---
296
443
297
444
## 8 GitHub Issues Filed
@@ -311,11 +458,11 @@ Related library issue: [ogc-client-CSAPI_2#166](https://github.com/OS4CSAPI/ogc-
|`d331433`| OpenSky: keep timestamp field for Go server (schema validation requires it) |
327
474
|`eed2e4d`| OpenSky: replace NaN strings with 0.0 for Go server (strict JSON validation) |
328
-
329
-
**Action needed:** Push to origin before continuing.
475
+
|`b7e551f`| feat: dual-publish support for all 8 remaining publishers |
476
+
|`906ae33`| feat: ISS bootstrap + bootstrap_helpers OSH_BASE_URL fix |
477
+
|`e7f792a`| fix: per-station unique datastream UIDs for Go server bootstraps |
478
+
|`92f584b`| fix: add limit=1000 to find_by_uid for Go server pagination |
479
+
|`3a02268`| fix: search subdeployments under parent, fix USGS Water station key |
480
+
|`62b78a3`| fix: ensure result.timestamp present for Go server schema validation |
330
481
331
482
### ogc-csapi-explorer
332
483
333
484
Commit `2f0869a` (Go server `@link.href` compat) already pushed.
334
485
335
486
---
336
487
337
-
## 10 Next Steps — Remaining Publisher Migration
488
+
## 10 Lessons Learned
489
+
490
+
### 10.1 Go Server Requires Explicit Everything
491
+
492
+
SensorHub is lenient — auto-generating UIDs, accepting partial results, filling timestamps from envelope fields. The Go server enforces strict PostgreSQL constraints and JSON schema validation. Every field must be explicit.
338
493
339
-
### Phase 1: Push existing work
340
-
1. Push 6 unpushed OSHConnect-Python commits to GitHub
For each publisher, apply the dual-publish pattern (§6):
496
+
The `find_by_uid()` pattern (check if exists, skip or create) breaks when the server ignores the `uid` query parameter and pagination hides existing resources. The `&limit=1000` workaround is fragile for large deployments.
344
497
345
-
| Priority | Publisher | Rationale |
346
-
|----------|-----------|-----------|
347
-
| 1 | ISS | Simplest (1 system, 2 DS). Quick win to validate pattern. |
| 6 | USGS Water | 8 stations, similar structure. |
353
-
| 7 | NDBC BuoyCAM | Image observations — may require Go server testing for binary/URL payloads. |
354
-
| 8 | USGS NIMS | Image observations — same considerations as BuoyCAM. |
498
+
### 10.3 Multi-Station Publishers Need Per-Station UIDs
355
499
356
-
### Phase 3: Verification
357
-
- Confirm all Go server services running with 0 errors
358
-
- Run Explorer smoke test against Go server
359
-
- Update health-check dashboard to monitor Go server publishers
500
+
SensorHub treats datastream UIDs as optional and per-system scoped. The Go server's global `UNIQUE` constraint on `unique_identifier` means every datastream across the entire database must have a distinct UID.
360
501
361
-
### Phase 4: Documentation
362
-
- Update this report with final status
363
-
- Update `Publisher_Fleet_Portability_Plan.md` to reference dual-publish capability
364
-
- Update `README.md` with Go server instructions
502
+
### 10.4 Subdeployment Hierarchy Is Not Transparent
503
+
504
+
The Go server's `/deployments` endpoint only returns top-level deployments. Bootstraps that create child deployments must search under the parent explicitly.
505
+
506
+
### 10.5 VM Deployment Workflow
507
+
508
+
The current file-copy deployment (staging repo → per-publisher directories) is error-prone. Multiple bootstrap failures were caused by stale code in publisher directories. A git-pull-based or symlink-based approach would be more reliable.
509
+
510
+
---
511
+
512
+
## 11 Future Work
513
+
514
+
-**File GitHub issues** for the 4 newly discovered Go server behaviors (§3.3)
515
+
-**Explorer smoke test** against Go server to verify map visualization
516
+
-**Consolidate VM deployment** — replace per-directory file copies with symlinks or a deploy script
517
+
-**UAS Simulator + Localizer** — evaluate Go server integration path
518
+
-**Monitoring** — add health-check dashboard for Go publisher services
519
+
-**CelesTrak resilience** — add retry/fallback for ISS TLE fetch timeouts
365
520
366
521
---
367
522
@@ -370,7 +525,7 @@ For each publisher, apply the dual-publish pattern (§6):
370
525
Services running on `129.80.248.53` as of 2026-04-17:
0 commit comments