Service Map
Olly is composed of ~21 services (14 Go services listed below plus the Python AI services - triage, balance, content). Each Go service owns its own PostgreSQL database and event stream. Services communicate synchronously via REST for blocking lookups (eligibility checks, provider lookups) and asynchronously via Kafka (single broker, versionless JSON events) for event-driven workflows. Every Go service follows the same internal layout: cmd/server/main.go -> config -> DB migrations -> dependency wiring -> HTTP server. The Go services run on dev-2; the Python AI services run on dev-1; APISIX is the gateway.
UK market
Olly operates in the UK (NHS-111, ICO/UK-GDPR, Companies House). US payer constructs - CPT/ICD-10 coding, ANSI X12 CARC, EDI 837/834/835, CMS fee schedules, HIPAA, COBRA, NPPES/CAQH - are not Olly's operating model. Where they appear below they are labelled 🚧 target-state or removed.
Service Summary
| Service | Port | Database | Publishes Events? | Consumes Events? | Notes |
|---|---|---|---|---|---|
| claims | 4001 | claims | Yes - claims.* | Yes - billing.payment.completed | Core adjudication engine; calls eligibility + provider synchronously |
| eligibility | 4002 | eligibility | Yes - eligibility.coverage.* | Yes - enrollment.*, provider.credentialing.* | Maintains accumulator balances; coverage/benefit checks over REST. (🚧 Target-state: FHIR 270/271 - not built) |
| enrollment | 4003 | enrollment | Yes - enrollment.* | Yes - billing.payment.missed | Temporal workflows for policy/enrolment lifecycle. (🚧 Target-state: COBRA timelines, EDI 834 ingest - not built; US constructs) |
| billing | 4004 | billing | Yes - billing.* | Yes - claims.claim.adjudicated, enrollment.* | Premium invoicing, payments, ledger, dunning (Stripe) |
| provider | 4005 | provider | Yes - provider.* | No | Temporal workflows for credentialing; provider directory + document processing. (🚧 Target-state: NPPES/CAQH - US, not built) |
| notifications | 4006 | notifications | No | Yes - claims.*, enrollment.*, billing.*, provider.* | Fan-in consumer; thin adapter over Novu - every transport (email, SMS, push, in-app) flows through Novu workflows; callers must not invoke FCM/Twilio/SendGrid directly |
| policy-admin | 4007 | policy_admin | No | No | Manages plan configurations, benefit rules, rate tables; feeds OpenSearch |
| triage | 4008 | triage | No | No | AI-assisted symptom triage and clinical routing |
| care | 4009 | care | No | No | Care management, chronic condition tracking, care plans |
| group-scheme | 4010 | group_scheme | No | No | Employer group setup, census management, open enrollment windows |
| broker-api | 4011 | broker | No | No | Broker/agent commission tracking and quoting |
| consent | 4012 | consent | Yes - consent.* | No | Consent records + audit (UK-GDPR/ICO basis, not HIPAA) |
| document-service | 4013 | documents | No | No | Document generation + object storage + signed-URL delivery |
| member-portal-api | 4014 | member_portal | No | No | BFF for member web portal; aggregates claims, coverage, billing data |
Service Patterns
Outbox Pattern
Every service that publishes to Kafka uses the transactional outbox pattern. Within the same database transaction as the business write, the service inserts a row into its local outbox table containing the topic, key, and serialized Avro payload. A background goroutine polls the outbox table, publishes each row to Kafka, then deletes it. This guarantees exactly-once semantics between the database state and the Kafka event - a service restart between publish and delete is safe because the outbox row will be re-published on restart (idempotent consumers deduplicate using a Valkey set with a 24-hour TTL (Valkey container on dev-2 in shared dev; Memorystore for Redis/Valkey in prod GCP)).
Saga Pattern
Multi-step workflows that span service boundaries are implemented as choreography-based sagas. There is no central saga orchestrator. Each service listens for events it cares about, performs its local action, and emits the next event. Compensation events handle rollback paths (e.g., enrollment.enrollment.cancelled rolls back pending coverage records and staged invoices). Temporal is used for long-running sagas with durable timers - e.g. credentialing recheck schedules and grace-period expirations. (US-specific timers such as COBRA election windows are 🚧 target-state, not built - Olly is UK.)
Projection Tables
Services that need to query data owned by another service maintain local projection tables populated by Kafka events. For example, the Claims Service maintains a member_accumulators projection updated by eligibility.coverage.verified events. This avoids synchronous cross-service queries for hot-path operations and eliminates inter-service coupling at query time.
Internal vs External Routes
Routes prefixed /internal/ bypass JWT middleware - they are accessible only within the service network (Docker network isolation in shared dev; the prod GCP posture is target-state). External routes under /v1/ require a valid Bearer token. (🚧 Target-state: OPA authorization and EDI ingest endpoints for Mirth Connect - EDI 837/834 is a US construct and is not built.)
Inter-Service Call Graph (Synchronous)
The following shows synchronous HTTP calls between services. Async Kafka flows are covered in Event Flow.
FHIR / clinical store lives in triage, not claims
The clinical FHIR surface is not a HAPI server called by claims/eligibility. FHIR R4 lives in a GCP Healthcare API store (project olly-platform-dev, region europe-west2 = UK, dataset olly-fhir, store triage), written only by the triage service from analysed media and ingested clinical documents (FHIR R4 transaction Bundles), authed keyless via Workload Identity Federation. See Triage. Claims/eligibility do not read or write FHIR today.
🚧 Target-state (not built, 0 code): a HAPI/CMS-style interoperability layer - CMS-9115 Patient-Access / Provider-Directory / Payer-to-Payer APIs, SMART-on-FHIR, $export, FHIR 270/271 eligibility, ICD-10/CPT coding via an AI platform, and Mirth EDI 837/834 ingest. These are US-payer constructs on the roadmap (Phase P2), not current architecture, and Olly is UK.
