Quick Start
Prerequisites
- The AJ FHIR Platform running (HAPI FHIR on :8080, Auth Server on :9000)
- The Consent Manager running (:8082)
- A SYSTEM-scoped token from the Auth Server for the consent gate
1. Get a SYSTEM-scoped token
The Referral Module calls the Consent Manager's /api/consent/evaluate endpoint using a system token. Generate one:
curl -X POST http://localhost:9000/oauth2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=referral-service&client_secret=secret&scope=SYSTEM"
Use the returned access_token as CONSENT_SERVICE_TOKEN.
2. Configure environment
# Required
export FHIR_BASE_URL=http://localhost:8080/fhir
export FHIR_SERVICE_TOKEN=<service-account-token>
export CONSENT_MANAGER_URL=http://localhost:8082
export CONSENT_SERVICE_TOKEN=<system-scoped-token>
# JWT validation
export JWT_EXPECTED_ISSUER=http://localhost:9000
export JWT_EXPECTED_AUDIENCE=http://localhost:8080/fhir
# Database
export DB_URL=jdbc:postgresql://localhost:5432/ajfhir_referral
export DB_USER=ajfhir
export DB_PASS=your-password
Consent service token required
If CONSENT_SERVICE_TOKEN is blank in a non-test profile, the application throws IllegalStateException at startup. Without this token the consent gate cannot function and no referral can be sent.
3. Start with Docker Compose
referral:
image: ajfhir/referral:1.0.0
ports:
- "8083:8083"
environment:
DB_URL: jdbc:postgresql://postgres:5432/ajfhir_referral
DB_USER: ajfhir
DB_PASS: ${DB_PASS}
FHIR_BASE_URL: http://hapi-fhir:8080/fhir
FHIR_SERVICE_TOKEN: ${FHIR_SERVICE_TOKEN}
CONSENT_MANAGER_URL: http://consent-manager:8082
CONSENT_SERVICE_TOKEN: ${CONSENT_SERVICE_TOKEN}
JWT_EXPECTED_ISSUER: ${JWT_EXPECTED_ISSUER}
JWT_EXPECTED_AUDIENCE: ${JWT_EXPECTED_AUDIENCE}
depends_on:
- postgres
- hapi-fhir
- consent-manager
docker compose up -d referral
4. Verify
curl http://localhost:8083/actuator/health
# {"status":"UP"}
5. Send your first referral
Step 1: Create a draft referral
curl -X POST http://localhost:8083/api/referrals \
-H "Authorization: Bearer <clinician-token>" \
-H "Content-Type: application/json" \
-d '{
"patientId": "Patient/ePatient-8675309",
"requesterId": "Practitioner/dr-smith",
"performerId": "Organization/royal-london-cardiology",
"receivingFacilityClientId": "akhester-smart-client",
"referralCode": "103696004",
"referralDisplay": "Cardiology referral",
"priority": "ROUTINE",
"reasonCodes": ["I20.9"],
"clinicalNote": "Chest pain and elevated troponin.",
"sharedResourceTypes": ["Observation", "Condition", "DiagnosticReport"],
"sendingOrganisationId": "Organization/anytown-gp",
"receivingOrganisationId": "Organization/royal-london-cardiology"
}'
Note the id from the response.
Step 2: Send it (consent gate runs here)
curl -X POST http://localhost:8083/api/referrals/1/send \
-H "Authorization: Bearer <clinician-token>"
If the patient has active consent for the receiving facility, the response is 200 with status: ACTIVE.
If consent is missing, the response is 422:
{
"code": "CONSENT_GATE_FAILED",
"message": "Cannot send referral — patient has not consented to share Condition with akhester-smart-client. Ask the patient to grant consent via the patient portal."
}
Step 3: Receiving facility accepts
curl -X PATCH http://localhost:8083/api/referrals/1/tasks/1 \
-H "Authorization: Bearer <receiving-clinician-token>" \
-H "Content-Type: application/json" \
-d '{ "status": "ACCEPTED" }'
Next: Architecture →