# khiem-nguyen-ict/fhir-fullstack-architecture-playground architecture

> Architecture diagram of the GitHub repository khiem-nguyen-ict/fhir-fullstack-architecture-playground, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-24). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground
- Repository: https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground

## Overview

1. **Overall shape**
   - This repo is a three-tier demo stack: **React frontend → GraphQL BFF → Spring Boot patient service → database**.
   - It is designed to show how a UI can stay decoupled from a domain service that exposes both CRUD and FHIR-shaped reads.

2. **Frontend boundary**
   - `frontend/` is a **Vite + React** single-page app.
   - Its only backend dependency is the **GraphQL endpoint** exposed by the BFF; it does not call the patient service directly.
   - The frontend’s responsibility is UI state, rendering, and user actions for listing/adding/deleting patients.

3. **BFF boundary**
   - `bff/` is a **Node.js Apollo GraphQL gateway**.
   - It translates frontend operations into calls against the patient service’s REST API via `patientServiceClient.js`.
   - `schema.js` defines the public GraphQL contract, while `resolvers.js` maps queries/mutations to backend calls.

4. **Patient service boundary**
   - `services/patient-service/` is the system of record for patient data.
   - It is a **Spring Boot 3 / Java 17** service with a clear internal split:
     - `PatientController` for HTTP endpoints
     - `PatientRepository` for persistence access
     - `Patient` and `PatientRequest` for domain/input models
     - `FhirMapper` for converting internal records to FHIR-shaped responses
   - This service owns the data model and the persistence rules.

5. **Persistence layer**
   - The patient service uses **Postgres in Docker** and **H2 when run standalone**.
   - The architecture deliberately makes persistence swappable for local development versus the full stack demo.
   - `DataSeeder` populates sample patients on first boot, which matters because the UI and smoke tests assume starter data exists.

6. **FHIR-shaped API layer**
   - The patient service exposes two read models:
     - a normal REST CRUD API under `/api/patients`
     - a FHIR R4-shaped read API under `/fhir/Patient`
   - The FHIR endpoint is not a full FHIR server; it is a **FHIR-shaped projection** of the same underlying patient records, likely wrapped as a Bundle and/or Patient resources.

7. **Request flow for user actions**
   - A typical create/delete/list flow is:
     - React UI triggers a GraphQL operation
     - BFF resolver calls patient-service REST
     - patient-service persists or reads from the database
     - response returns back through the BFF to the browser
   - This keeps the frontend insulated from REST details and lets the BFF act as an adaptation layer.

8. **Direct service access paths**
   - The repo intentionally supports multiple access modes for the patient service:
     - direct REST CRUD for operational use
     - direct FHIR-shaped reads for interoperability demos
     - GraphQL via BFF for the UI
   - That separation is useful for comparing client-facing API styles against one shared domain service.

9. **Containerization and runtime composition**
   - Each major piece has its own `Dockerfile`, and `infra/docker-compose.yml` wires them together.
   - The compose setup includes **Postgres + frontend + BFF + patient service**, enabling a one-command full-circle demo.
   - Port separation is part of the architecture: frontend on `5173`, BFF on `4000`, patient service on `8081`.

10. **Architecture diagram boundaries to show**
   - Draw **three application boxes** plus **one database box**:
     - Browser/React UI
     - GraphQL BFF
     - Patient service
     - Postgres/H2
   - Show **frontend only talking to BFF**, **BFF only talking to REST**, and **patient service owning persistence**.
   - Show a second read path from patient service to a **FHIR-shaped response** to emphasize interoperability without a dedicated FHIR server.

11. **Operational concerns**
   - The patient service exposes `/health`, which suggests simple container/service health checking.
   - The repository is optimized for local experimentation and architecture demos rather than production hardening; the clearest design goal is demonstrating layer separation, not maximizing framework complexity.

12. **Key takeaway**
   - The architectural center of gravity is the **BFF pattern**: UI concerns are separated from service concerns, and the service itself provides both a conventional CRUD surface and a FHIR-like read projection over the same data.

Main entry points: [`services/patient-service/src/main/java/com/example/patient/PatientController.java`](https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/services/patient-service/src/main/java/com/example/patient/PatientController.java) (Controller), [`infra/docker-compose.yml`](https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/infra/docker-compose.yml) (Compose stack), [`services/patient-service/src/main/java/com/example/patient/PatientRepository.java`](https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/services/patient-service/src/main/java/com/example/patient/PatientRepository.java) (Repository), [`services/patient-service/src/main/java/com/example/patient/PatientServiceApplication.java`](https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/services/patient-service/src/main/java/com/example/patient/PatientServiceApplication.java) (Service app)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_client["Frontend"]
  node_browser_ui["React UI<br/>Vite SPA<br/>[App.jsx]"]
  node_graphql_client["GraphQL client<br/>UI transport<br/>[graphqlClient.js]"]
  node_frontend_entry["App entry<br/>React bootstrap<br/>[main.jsx]"]
end

subgraph group_gateway["BFF"]
  node_bff_server["GraphQL server<br/>Apollo BFF<br/>[index.js]"]
  node_schema["Schema<br/>GraphQL contract<br/>[schema.js]"]
  node_resolvers["Resolvers<br/>GraphQL mapping<br/>[resolvers.js]"]
  node_patient_client["REST client<br/>HTTP adapter"]
end

subgraph group_service["Patient Service"]
  node_service_app["Service app<br/>Spring Boot"]
  node_controller["Controller<br/>REST API"]
  node_fhir_mapper["FHIR mapper<br/>Projection<br/>[FhirMapper.java]"]
  node_repository["Repository<br/>Persistence access"]
  node_patient_model["Patient model<br/>Domain model<br/>[Patient.java]"]
  node_patient_request["Request model<br/>Input DTO"]
  node_data_seeder["Seeder<br/>Bootstrap data<br/>[DataSeeder.java]"]
  node_fhir_read["FHIR read<br/>FHIR-shaped API"]
end

subgraph group_infra["Infra"]
  node_persistence[("Database<br/>Postgres/H2<br/>[docker-compose.yml]")]
  node_compose["Compose stack<br/>Docker Compose<br/>[docker-compose.yml]"]
end

node_frontend_entry -->|"renders"| node_browser_ui
node_browser_ui -->|"queries"| node_graphql_client
node_graphql_client -->|"GraphQL"| node_bff_server
node_bff_server -->|"exposes"| node_schema
node_schema -->|"binds"| node_resolvers
node_resolvers -->|"calls"| node_patient_client
node_patient_client -->|"REST"| node_controller
node_controller -->|"uses"| node_repository
node_controller -->|"projects"| node_fhir_mapper
node_repository -->|"stores"| node_patient_model
node_controller -->|"accepts"| node_patient_request
node_service_app -->|"hosts"| node_controller
node_service_app -->|"initializes"| node_data_seeder
node_data_seeder -->|"seeds"| node_repository
node_repository -->|"reads/writes"| node_persistence
node_controller -->|"serves"| node_fhir_read
node_compose -->|"runs"| node_bff_server
node_compose -->|"runs"| node_service_app
node_compose -->|"runs"| node_browser_ui
node_compose -->|"runs"| node_persistence

click node_browser_ui "https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/frontend/src/App.jsx"
click node_graphql_client "https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/frontend/src/graphqlClient.js"
click node_frontend_entry "https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/frontend/src/main.jsx"
click node_bff_server "https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/bff/index.js"
click node_schema "https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/bff/schema.js"
click node_resolvers "https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/bff/resolvers.js"
click node_patient_client "https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/bff/patientServiceClient.js"
click node_service_app "https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/services/patient-service/src/main/java/com/example/patient/PatientServiceApplication.java"
click node_controller "https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/services/patient-service/src/main/java/com/example/patient/PatientController.java"
click node_fhir_mapper "https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/services/patient-service/src/main/java/com/example/patient/FhirMapper.java"
click node_repository "https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/services/patient-service/src/main/java/com/example/patient/PatientRepository.java"
click node_patient_model "https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/services/patient-service/src/main/java/com/example/patient/Patient.java"
click node_patient_request "https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/services/patient-service/src/main/java/com/example/patient/PatientRequest.java"
click node_data_seeder "https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/services/patient-service/src/main/java/com/example/patient/DataSeeder.java"
click node_persistence "https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/infra/docker-compose.yml"
click node_compose "https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/infra/docker-compose.yml"
click node_fhir_read "https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/services/patient-service/src/main/java/com/example/patient/PatientController.java"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_browser_ui,node_graphql_client,node_frontend_entry toneBlue
class node_bff_server,node_schema,node_resolvers,node_patient_client toneAmber
class node_service_app,node_controller,node_fhir_mapper,node_repository,node_patient_model,node_patient_request,node_data_seeder,node_fhir_read toneMint
class node_persistence,node_compose toneRose
```

## Components

### Frontend

React browser UI

- [React UI](https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/frontend/src/App.jsx): Vite SPA · Browser-facing patient list and mutation UI · `frontend/src/App.jsx`
- [GraphQL client](https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/frontend/src/graphqlClient.js): UI transport · Browser-side GraphQL request helper · `frontend/src/graphqlClient.js`
- [App entry](https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/frontend/src/main.jsx): React bootstrap · Frontend startup and rendering entrypoint · `frontend/src/main.jsx`

### BFF

GraphQL adaptation layer

- [GraphQL server](https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/bff/index.js): Apollo BFF · Node.js GraphQL gateway exposed to the UI · `bff/index.js`
- [Schema](https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/bff/schema.js): GraphQL contract · Public queries and mutations for the frontend · `bff/schema.js`
- [Resolvers](https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/bff/resolvers.js): GraphQL mapping · Maps GraphQL operations to patient-service calls · `bff/resolvers.js`
- [REST client](https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/bff/patientServiceClient.js): HTTP adapter · BFF client for the patient service REST API · `bff/patientServiceClient.js`

### Patient Service

Spring Boot domain service

- [Service app](https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/services/patient-service/src/main/java/com/example/patient/PatientServiceApplication.java): Spring Boot · Patient system of record runtime · `services/patient-service/src/main/java/com/example/patient/PatientServiceApplication.java`
- [Controller](https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/services/patient-service/src/main/java/com/example/patient/PatientController.java): REST API · CRUD and FHIR-shaped HTTP endpoints · `services/patient-service/src/main/java/com/example/patient/PatientController.java`
- [FHIR mapper](https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/services/patient-service/src/main/java/com/example/patient/FhirMapper.java): Projection · Converts patient records to FHIR-shaped responses · `services/patient-service/src/main/java/com/example/patient/FhirMapper.java`
- [Repository](https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/services/patient-service/src/main/java/com/example/patient/PatientRepository.java): Persistence access · Data access boundary for patients · `services/patient-service/src/main/java/com/example/patient/PatientRepository.java`
- [Patient model](https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/services/patient-service/src/main/java/com/example/patient/Patient.java): Domain model · Persistent patient entity · `services/patient-service/src/main/java/com/example/patient/Patient.java`
- [Request model](https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/services/patient-service/src/main/java/com/example/patient/PatientRequest.java): Input DTO · Create/update request payload model · `services/patient-service/src/main/java/com/example/patient/PatientRequest.java`
- [Seeder](https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/services/patient-service/src/main/java/com/example/patient/DataSeeder.java): Bootstrap data · Loads starter patients on first boot · `services/patient-service/src/main/java/com/example/patient/DataSeeder.java`
- [FHIR read](https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/services/patient-service/src/main/java/com/example/patient/PatientController.java): FHIR-shaped API · FHIR R4-shaped projection over patient records · `services/patient-service/src/main/java/com/example/patient/PatientController.java`

### Infra

Container and persistence wiring

- [Database](https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/infra/docker-compose.yml): Postgres/H2 · Swappable local or container persistence store · `infra/docker-compose.yml`
- [Compose stack](https://github.com/khiem-nguyen-ict/fhir-fullstack-architecture-playground/blob/main/infra/docker-compose.yml): Docker Compose · Wires frontend, BFF, service, and database together · `infra/docker-compose.yml`

## Connections

- App entry → React UI: renders · Bootstraps the UI shell
- React UI → GraphQL client: queries · UI issues GraphQL operations
- GraphQL client → GraphQL server: GraphQL · Frontend talks only to the BFF endpoint
- GraphQL server → Schema: exposes · Serves the public GraphQL contract
- Schema → Resolvers: binds · Schema fields are resolved by implementation handlers
- Resolvers → REST client: calls · Resolvers translate operations into REST requests
- REST client → Controller: REST · BFF invokes the patient service API
- Controller → Repository: uses · HTTP layer delegates persistence work
- Controller → FHIR mapper: projects · FHIR endpoint uses the mapper for read projection
- Repository → Patient model: stores · Repository persists patient entities
- Controller → Request model: accepts · CRUD endpoints consume request DTOs
- Service app → Controller: hosts · Spring Boot runtime serves the HTTP layer
- Service app → Seeder: initializes · Bootstraps sample data on startup
- Seeder → Repository: seeds · Seeder populates the patient store
- Repository → Database: reads/writes · Data access goes to the underlying database
- Controller → FHIR read: serves · FHIR-shaped GETs are exposed alongside CRUD
- Compose stack → GraphQL server: runs · Compose starts the gateway service
- Compose stack → Service app: runs · Compose starts the patient service
- Compose stack → React UI: runs · Compose starts the frontend container
- Compose stack → Database: runs · Compose provides the database container
