ServicesPhoenix Search

Phoenix Search

FastAPI search microservice for patient and user lookup

👤 Sai Tharun

Phoenix Search is a FastAPI search microservice for patient and user lookup. It serves authenticated search requests from LiveHealth surfaces, queries the user_details Elasticsearch index, and uses MySQL plus Redis for source data, session context, rate limiting, and operational checks.

CDC is part of Phoenix Search. The CDC pipeline keeps the Elasticsearch projection in sync from MySQL through Debezium, Redpanda, the Phoenix CDC consumer, the user_meta projection table, and the Elasticsearch ingest pipeline.

Start with Start Here for the reading order. For the full high-level and low-level system view, see Architecture. For frontend endpoint and ephemeral-token auth, see Auth and Endpoints.

Repository Information

PropertyValue
Repositoryphoenix-search
LanguagePython 3.13+
Main Branchmain
FrameworkFastAPI
Search BackendElasticsearch
Primary Indexuser_details
CDC RuntimePython consumer + Debezium + Redpanda

Production Snapshot

Latest saved dashboard screenshots for production IN show Phoenix Search handling the observed traffic window with healthy service and Elasticsearch signals. The full migration evidence, old-vs-new index comparison, and OpenTelemetry notes are in Post-Migration Results.

SignalObserved Production Value
API request error rate0% in the HTTP service dashboard
Main endpointPOST /api/v1/users/search, about 97% of endpoint time
Search endpoint latencyMedian about 22.76 ms, p95 about 47.67 ms
ES query latencyp50 about 2.5 ms, p95 about 4.75 ms, p99 about 4.95 ms
CDC health1, with ES document freshness around 3.6s
ES clusterGREEN, 3 active data nodes
user_details indexAbout 157.44M docs, 67.61 GB primary, 135.75 GB total
Storage reductionAbout 47% lower than the old userdetails index, roughly 50% in practical terms

The detailed dashboard snapshot and migration results live in Post-Migration Results.

Clone Repository

git clone git@github.com:CrelioHealth/phoenix-search.git

Tech Stack

CategoryTechnologyPurpose
RuntimePython 3.13+API and CDC consumer runtime
Web FrameworkFastAPIHTTP API server
SearchElasticsearchPatient and user search index
Cache / SessionsRedisDjango session lookup, KV support, rate-limit config
DatabaseMySQLSource-of-truth user data and user_meta projection
CDC BrokerRedpandaKafka-compatible event transport
CDC SourceDebezium MySQL ConnectorMySQL binlog capture
CLI / Packaginguv, TyperLocal commands and project execution
ObservabilityPrometheus, OpenTelemetry, HyperDX, SentryMetrics, traces, logs, and errors

System Architecture Overview


Key Components

1. FastAPI Application (search/web/application.py)

The app factory registers monitoring routes at the root and API routes under /api. Production traffic can arrive behind the ALB path prefix /phoenix-search; StripPrefixMiddleware removes that prefix before FastAPI routing.

Route AreaRegistered PathNotes
Home and health/, /health, /health/live, /health/readyMonitoring routes are public
Metrics/metricsPrometheus exposition endpoint
OpenAPI/api/openapi.jsonFastAPI OpenAPI document
Docs/docsFastAPI Swagger UI
User Search/api/v1/users/searchAuthenticated user search API

The domain owns its router, schemas, service, repository, filters, and Elasticsearch query builders.

FileRole
router.pyFastAPI endpoints and dependencies
schemas.pyRequest and response models
service.pySession-aware search orchestration, hit bucketing, MySQL detail lookup
repository.pyElasticsearch query execution and circuit-breaker handling
constant.pySEARCH_MAPPING keys and searchable fields

Search requests are scoped by the authenticated session. The service resolves lab, branch, organization, referral, and multi-center constraints before querying Elasticsearch, sends ES routing from the resolved lab_id values, then groups hits into registered, samples, orders, and other_labs.

3. Authentication and Session Context

SessionAuthMiddleware authenticates every non-guest route. It supports:

Client TypeAuth Mechanism
Web appsessionid cookie resolved from Redis-backed Django sessions
Mobile appBearer JWT when X-App-Name is present
Ephemeral web flowBearer JWT without X-App-Name

The validated session is stored on request state and in a context variable so route dependencies can resolve lab_id, organization scope, and search restrictions.

4. Lifecycle and Observability (search/web/lifespan.py)

Startup initializes OpenTelemetry, Prometheus instrumentation, Elasticsearch, MySQL, Redis, and rate-limit Redis. A background CDC freshness probe periodically queries the newest last_updated_time in Elasticsearch and exposes freshness through /health plus metrics.

5. CDC Subsystem (cdc/)

CDC is documented in this section because it is the write-side sync path for Phoenix Search. It is not a separate service in the docs navigation. See Architecture for the system view, CDC for the pipeline, and Operations for runbooks.


Local Setup

Prerequisites

ToolVersion / Requirement
Python3.13+
uvLatest
DockerLatest
MySQL8.x source database; hosted externally for dev, Docker for tests

Quick Start

make install
cp .env.example .env
cp docker/.env.example docker/.env
make up-dev
make seed
make run

The API runs on http://localhost:8000, and FastAPI docs are available at http://localhost:8000/docs.

Services and Ports

ServiceDevTestDescription
API80008010FastAPI server
Elasticsearch92109212Search backend
Kibana5601-Elasticsearch dashboard
RedisinternalinternalCache, sessions, rate-limit state
MySQL33063308External dev DB, Docker test DB
HyperDX8080-Observability UI

Core Flows

Search Request

Detail Lookup

MySQL to Elasticsearch Sync


Make Targets

CommandWhat it does
make installInstall Python dependencies
make runStart the API server
make up-devStart Redis, Elasticsearch, and Kibana
make up-allStart all local infra plus HyperDX
make downStop all containers
make testRun unit tests without Docker
make test-dockerRun the full suite in Docker
make lintRun Ruff and mypy
make seedSeed 50 users across 2 labs
make seed-resetDrop, recreate, and seed fresh local data
make register-pipelineRegister the Elasticsearch ingest pipeline
make run-cdcStart the local CDC stack
make connector-statusShow Debezium connector health
make backfill-migratePopulate the MySQL projection table
make backfill-runPush projected data into Elasticsearch

Source References

ConcernSource
App factory and ALB prefix handlingsearch/web/application.py
Route registrationsearch/web/api/router.py
User search endpointssearch/domains/user_search/router.py
User search request and response modelssearch/domains/user_search/schemas.py
Search orchestrationsearch/domains/user_search/service.py
Elasticsearch query executionsearch/domains/user_search/repository.py
Query shape routingsearch/domains/user_search/query.py
CDC runbookcdc/RUNBOOK.md
CDC settingscdc/consumers/config.py

On this page