Skip to content

feat: go export microservice drop in with gRPC comms and thin API shim#2153

Draft
PeterBaker0 wants to merge 4 commits into
FAIMS:mainfrom
PeterBaker0:feat/go-export-service-3d4e
Draft

feat: go export microservice drop in with gRPC comms and thin API shim#2153
PeterBaker0 wants to merge 4 commits into
FAIMS:mainfrom
PeterBaker0:feat/go-export-service-3d4e

Conversation

@PeterBaker0

Copy link
Copy Markdown
Contributor

Summary

Introduces a Go gRPC export sidecar that performs the heavy lifting of notebook exports while Conductor keeps auth, download-token validation, and HTTP response headers unchanged. The API gains a thin bridge (exportHttpStreamer) that streams gRPC FileChunks straight to the browser and falls back to the existing Node exporters when the sidecar is unavailable.

This is a drop-in rollout: with no export-service configured, behaviour stays on the legacy Node path.

Go export service (export-service/)

  • New gRPC service implementing all export formats: CSV, photo ZIP, GeoJSON, KML, full notebook ZIP, and JSON records
  • Reads directly from CouchDB; streams output in configurable chunks (32 KiB default)
  • Shared protobuf contract at proto/export.proto with committed Go bindings under internal/pb
  • Health RPC for readiness checks
  • Optional shared-secret auth via x-export-service-secret metadata
  • Ports key Node export behaviour: deleted related-record stripping, attachment field detection (TakePhoto + FileUploader), CSV escaping, spatial empty output, structured gRPC error codes
  • Optional runtime profiling (EXPORT_PROFILE=true) for memory, goroutines, and active export stats
  • Dockerfile for container deployment; CI runs go test ./... and go build on every PR

API shim (api/src/services/)

  • exportServiceClient — lazy gRPC client from shared proto; maps export payloads to protobuf requests
  • exportHttpStreamer — unified routing for all download routes and GET /:id/records/
  • exportTypes — shared TypeScript types for formats, rollout mode, and gRPC payloads
  • Rollout controlled by env:
    • EXPORT_SERVICE_GRPC_ADDRESS / EXPORT_SERVICE_GRPC_URL — sidecar address
    • EXPORT_SERVICE_MODEauto (default), grpc, or legacy
    • EXPORT_SERVICE_SHARED_SECRET — optional mutual auth
    • EXPORT_SERVICE_GRPC_DEADLINE_MS — optional call deadline
  • auto mode: pre-stream gRPC failures fall back to legacy Node exporters; mid-stream failures destroy the HTTP response (partial downloads cannot be safely restarted)
  • grpc mode: no fallback — sidecar must be available
  • Tests default to legacy mode so existing API tests are unaffected

Configuration

Conductor (API)

Variable Default Description
EXPORT_SERVICE_GRPC_ADDRESS (unset) gRPC address of the sidecar; unset = legacy only
EXPORT_SERVICE_MODE auto auto, grpc, or legacy
EXPORT_SERVICE_SHARED_SECRET (unset) Optional shared secret sent as gRPC metadata
EXPORT_SERVICE_GRPC_DEADLINE_MS (unset) Optional gRPC call deadline in ms

Go export service

Variable Default Description
EXPORT_GRPC_ADDR :9090 Listen address
COUCHDB_INTERNAL_URL http://localhost:5984 CouchDB base URL
COUCHDB_USER / COUCHDB_PASSWORD admin / password CouchDB credentials
EXPORT_PROFILE false Print runtime stats every second

See export-service/README.md for local development commands.

Test plan

  • cd export-service && go test ./... — unit tests for CSV escaping, filenames, deleted related refs, attachments, spatial output, auth, error mapping
  • cd api && pnpm test — includes exportServiceStreamer.test.ts (grpc piping, legacy mode, mid-stream failure, auto fallback)
  • CI Build & Lint workflow passes Go export-service step
  • Legacy path (no sidecar): leave EXPORT_SERVICE_GRPC_ADDRESS unset; verify CSV, photo ZIP, GeoJSON, KML, full export, and JSON records download as before
  • Auto rollout: set EXPORT_SERVICE_GRPC_ADDRESS=localhost:9090, EXPORT_SERVICE_MODE=auto; start sidecar; confirm exports stream via gRPC; stop sidecar and confirm pre-stream fallback to Node
  • Forced gRPC: set EXPORT_SERVICE_MODE=grpc; confirm exports fail clearly when sidecar is down (no silent fallback)
  • Shared secret: set matching EXPORT_SERVICE_SHARED_SECRET on API and sidecar; confirm unauthenticated gRPC calls are rejected
  • Large notebook: full export with attachments — compare output size and filenames against legacy Node export
  • Client disconnect: cancel a large download mid-stream; confirm sidecar export is cancelled cleanly

@PeterBaker0
PeterBaker0 marked this pull request as draft June 23, 2026 06:00
@PeterBaker0
PeterBaker0 force-pushed the feat/go-export-service-3d4e branch from a979119 to 1bc1a2a Compare June 24, 2026 04:05
cursoragent and others added 4 commits June 24, 2026 14:21
Co-authored-by: Peter Baker <PeterBaker0@users.noreply.github.com>
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Signed-off-by: Peter Baker <peter.baker122@csiro.au>
… tests, and CI

Bring the Go gRPC export sidecar closer to production parity with the Node
exporters by fixing deleted-related-record stripping, broadening attachment
ZIP field detection, hardening CouchDB HTTP calls, and adding rollout controls.

Go service:
- Port stripDeletedRelatedRefs for CSV, spatial, full, and JSON records exports
- Include TakePhoto and FileUploader fields in attachment ZIP exports
- Add Health RPC, optional shared-secret auth, structured gRPC error codes
- Add EXPORT_FORMAT_JSON_RECORDS and configurable chunk size
- Add unit tests for CSV escaping, filenames, related refs, attachments, spatial empty output, auth, and error mapping

API:
- Replace ad-hoc exportGrpcClient usage with exportHttpStreamer bridge
- Support EXPORT_SERVICE_MODE (auto|grpc|legacy) and GRPC_URL alias
- Wire all download routes and GET /:id/records/ through the unified bridge
- Add exportServiceStreamer tests with injectable client and rollout config

CI:
- Run go test and build for export-service on every PR

Co-authored-by: Peter Baker <PeterBaker0@users.noreply.github.com>
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Signed-off-by: Peter Baker <peter.baker122@csiro.au>
@PeterBaker0
PeterBaker0 force-pushed the feat/go-export-service-3d4e branch from 1bc1a2a to 5a56cef Compare June 24, 2026 04:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants