Skip to content

The right blood type isn't enough: it has to be someone who can get there

A donor register that matches each request on blood-group compatibility and on whether the donor can actually reach the hospital. One platform serves a web admin and a mobile client from the same records.

Register

12,486 donors · each placed by division, district and sub-district, chosen at registration

Add donorThu 17 Sep 2026
Blood group O−Division DhakaDistrict: AnySub-district: AnyEligibility: All · resting shown greyed310 of 12,486 donors

Narrow the register

Blood group · whole register

O+3,828
B+3,562
A+3,104
AB+902
O−612
A−214
B−188
AB−76

Division · O negative only

Dhaka310
Chattogram98
Rajshahi52
Khulna44
Mymensingh36
Rangpur28
Sylhet24
Barishal20

O− O negative in Dhaka division

310 donors · sorted by district, then sub-district
DonorDistrictSub-districtLast givenEligibilityGiven
MHMahmudul HasanDhakaSavar16 Jun 2026Eligible since 14 Sep7
NJNusrat JahanDhakaSavar4 Jul 2026Resting until 2 Oct3
RHRakibul HasanDhakaDhamrai8 Jun 2026Eligible since 6 Sep6
JFJannatul FerdousDhakaKeraniganj12 Aug 2026Resting until 10 Nov2
ICImran ChowdhuryDhakaMirpur30 May 2026Eligible since 28 Aug8
SASabbir AhmedGazipurTongi3 Apr 2026Eligible since 2 Jul4
RARumana AfrozGazipurKaliakairNone yetEligible0
AAAshraful AlamKishoreganjKishoreganj Sadar21 Jul 2026Resting until 19 Oct5
MBMoushumi BegumKishoreganjBhairab6 May 2026Eligible since 4 Aug3
TRTanvir RahmanKishoreganjBajitpur28 Feb 2026Eligible since 29 May6
HRHabibur RahmanKishoreganjKatiadi17 Jun 2026Eligible since 15 Sep2
SPShahana ParvinNarayanganjRupganj9 Sep 2026Resting until 8 Dec4
MRMizanur RahmanTangailMirzapur15 Jan 2026Eligible since 15 Apr9
RKRokeya KhatunNarsingdiPalash2 Jun 2026Eligible since 31 Aug1
DHDelwar HossainManikganjSingair26 Mar 2026Eligible since 24 Jun5
Showing 1–15 of 310Sub-district decides who can be called for a request

Who, what, and how long

Industry

Healthcare & Dental Practices

Duration

16 weeks

Cooperation model

Fixed price, phased

Services
Platform engineeringMatching modelMobile API
Integrations
SMS gatewayTransactional emailPush notificationsMap tiles
Technologies
LaravelPHPMySQLSanctumBladeREST
Team
1 Project lead2 Backend engineers1 Mobile engineer

Client name withheld under NDA. Engagement details are shown to the extent our agreement permits.

The hard problem

  1. 01

    A donor register is only useful in the hours after a request. Matching on blood group alone produces a list mostly made of people two hundred miles away, and coordinators end up phoning down it by hand until they find someone close enough to matter.

    Addresses were free text, which made geographic matching impossible, not merely imprecise: there was nothing to query against. So group compatibility was the only available filter, and it produces a list ordered by nothing useful. The cost was paid in the worst hour, by a coordinator working a phone list while a hospital waited.

    Matching on compatibility and geography together, over a real three-level area hierarchy, so the first names a coordinator sees are the ones who can be at the hospital today. The same records serve the admin and the mobile client through parallel web and API controllers.

How the pieces fit

  1. 01

    Modeled the area hierarchy properly: division, district, sub-district

    Location is modeled as a true hierarchy of division, district and sub-district, so searches can widen gradually.

  2. 02

    Made matching compatibility crossed with reachability, never either alone

    Matching crosses compatibility with geography in one query, so the list is ordered by who can realistically attend.

  3. 03

    Served admin and mobile from one application with parallel web and API controllers

    Serving both from one application was chosen over a separate API service because two clients disagreeing about a donor's state is the failure that matters here.

  4. 04

    Recorded donation history so someone who gave three weeks ago isn't asked again

    Donation history suppresses anyone inside their recovery window automatically, and the suppression is visible on the donor's own profile.

  5. 05

    Let organizations hold their own request queues without forking the register

    Organization queues were added after the register worked, so the model was proven on one coordinator's workflow before it had to serve several.

Introduction

The system we were asked to build

The organization keeps a register of volunteer donors and connects them to urgent requests. We built the register, the matching, and the one application that serves both the coordinators' admin and the donors' phones.

A volunteer donor register whose value exists entirely in the hours after an urgent request. Coordinators were matching on blood group, getting a list mostly composed of people two hundred miles away, and phoning down it by hand until they found someone close enough to matter. The engagement covered the register, the matching and the two clients that read it.

Backend & Platform Engineering

01

Compatible and reachable

Matching crosses blood-group compatibility with a real area hierarchy, so the top of the list can actually attend.

Matching crosses blood-group compatibility with geography in one query, because a compatible donor four hours away isn't a match for a hospital that needs someone this afternoon. The result is ordered by who can realistically attend, which is the only ordering a coordinator can act on.

What shipped
  • Compatibility and geography resolved in one query
  • Ordered by who can actually attend today
  • Never group-filtered, then distance-sorted as an afterthought
Call list · REQ-2609-0418

O negative · Savar Community Medical Centre · compatibility and area in one query · ordered by travel time

CallingWiden to divisionThu 17 Sep 2026
O−

Savar Community Medical Centre

Ward 4 · Surgery · Bazar Road, Savar · raised 17 Sep, 10:36 am

Needed by

Today, 3:00 pm

Reach set on request

Within 60 min
8 callable2 resting118 beyond reach

Who can be there today

10 within 60 min of Savar
#DonorDistanceTravel timeAction
1MHMahmudul HasanSavar · 7 given · last 16 Jun2.4 km9 min01712-●●●●48Call
–NJNusrat JahanSavar · 3 given · last 4 Jul3.1 km12 minResting until 2 Oct
3AHArif HossainSavar · 5 given · last 2 May4.0 km15 min01819-●●●●06Call
4SRSadia RahmanSavar · 2 given · last 11 Mar5.6 km19 min01911-●●●●72Call
–KIKamrul IslamSavar · 9 given · last 23 Aug7.2 km24 minResting until 21 Nov
6TATahmina AkterSavar · 4 given · last 27 Apr8.9 km28 min01715-●●●●31Call
7RHRakibul HasanDhamrai · 6 given · last 8 Jun14.5 km34 min01552-●●●●90Call
8SSShirin SultanaSavar · 1 given · last 19 Jan11.8 km37 min01670-●●●●15Call
9ICImran ChowdhuryMirpur · 8 given · last 30 May17.0 km46 min01817-●●●●63Call
10FYFarhana YasminDhamrai · 3 given · last 14 Feb21.3 km52 min01937-●●●●24Call
118 more O negative donors in Dhaka district, over 60 min awayShow

How the list was made

one query
Registeredwhole register12,486
O negativegroup match612
Dhaka divisionarea, level 1310
Dhaka districtarea, level 2128
Within 60 min118 beyond reach10
Callable now2 resting, not callable8

Held back, and why

2 inside the 90-day windowGrayed, no number shown, can't be called
118 compatible, too farOver 60 min from Savar by road
0 contacted while ineligibleResting donors are excluded, not warned about
On screen

The list a coordinator actually rings for an O negative request in Savar, ordered by travel time: two donors grayed out by the 90-day rule, eight callable, and 118 more too far to matter.

Areas

Division, district and sub-district as records · donors pick theirs at registration · searches widen one level at a time

Add sub-districtThu 17 Sep 2026

Divisions

8 Division

Districts

64 District

Sub-districts

495 Sub-district

Donors placed

12,486 0 free-text addresses

Division 8 divisions

DivisionDistrictsDonors
Dhaka134,318
Chattogram112,146
Rajshahi81,402
Khulna101,188
Mymensingh41,036
Rangpur8904
Sylhet4812
Barishal6680

64 districts · 495 sub-districts in all

District Dhaka division

13 districts
DistrictDonorsO−
Dhaka1,486128
Kishoreganj1,20454
Gazipur41235
Narayanganj31825
Tangail23622
Narsingdi16414
Manikganj1129
Munshiganj1048
Faridpur987
Gopalganj563
Madaripur483
Rajbari421
Shariatpur381

4,318 donors310 O negative

Sub-district Kishoreganj district

donors in 7 sub-districts
1,204 donors54 O negative3 with none
Sub-districtDonorsO negative
Kishoreganj Sadar31817
Bhairab24614
Bajitpur17212
Katiadi15811
Karimganj131None registered0
Itna98None registered0
Nikli81None registered0

An O negative request in Itna finds nobody in its sub-district, so it widens one level to Kishoreganj (54), then to Dhaka division (310), never straight to all 12,486.

On screen

Eight divisions down to 495 sub-districts: Kishoreganj's 1,204 donors split across seven sub-districts, only 54 of them O negative and three sub-districts holding none.

02

Three-level geography

Division, district and sub-district stored as records, with no free-text address field.

Division, district and sub-district are records with real relationships, so a search can widen a step at a time (this sub-district, then the district, then the division) instead of jumping from nothing to everything. Donors select from the hierarchy at registration, which is what makes the data clean enough to match on at all.

What shipped
  • Three geographic levels as records, not free text
  • Searches widen one level at a time
  • Selected at registration, so the data stays matchable
03

One application, two clients

Parallel web and API controllers over the same records, so admin and phone never disagree.

Web controllers and API controllers sit side by side over the same models and the same authorization rules, so the admin and the mobile client can't disagree about a donor's state. Sanctum handles the API tokens; the shared layer beneath means a rule added for one client is enforced for the other by construction, with no second implementation to drift.

What shipped
  • Parallel web and API controllers over identical models
  • Shared authorization, so the two clients can't diverge
  • A rule added once is enforced for both
10:42
Urgent requestREQ-2609-0418Open
O−Savar Community Medical CentreWard 4 · SurgeryNeeded by today, 3:00 pm
You · Radio ColonyHospital
2.4 km away about 9 min

You can donate

Eligible since 14 Sep
Last gave 16 Jun90 days · 14 SepToday, day 93
Asked because your group matches and you are one of the closest in Savar.
I can goI can’t make it

The coordinator sees your reply on the same request

HomeRequestsHistoryProfile
On screen

The same request on the donor's phone: it reaches a donor 2.4 km away, the group matches, and the register already knows he became eligible on 14 Sep.

Mahmudul Hasan

DNR-0031-7742 · O negative · Radio Colony, Savar · registered 2 Oct 2024

Eligible since 14 SepOpen call listThu 17 Sep 2026
MHMahmudul HasanAge 31 · 7 donationsO−
DivisionDhaka
DistrictDhaka
Sub-districtSavar · Radio Colony

Phone01712-●●●●48

The 90-day gap

since the last donation

93 days since 16 Jun 2026 · cleared on 14 Sep

Resting · no requests
16 Jun · donatedday 90 · 14 Septoday · day 93

Suppression lifted automatically · the same state shows on his phone

7 donations

every gap at least 90 days
#DateWhereViaGap
716 Jun 2026Savar Community Medical CentreREQ-2606-0212106 days
62 Mar 2026Savar Community Medical CentreREQ-2603-0057102 days
520 Nov 2025Mirpur Crescent HospitalREQ-2511-0331101 days
411 Aug 2025Ashulia Garment Workers' DriveDrive, walk-in98 days
35 May 2025Savar Community Medical CentreREQ-2505-014097 days
228 Jan 2025Mirpur Crescent HospitalREQ-2501-0023106 days
114 Oct 2024Savar Community Medical CentreREQ-2410-0098First

Oct 2024 → today

Requests he received

nothing tidied away
17 Sep 2026REQ-2609-0418Savar Community Medical CentreSent 10:41 am · awaiting replyOpen
15 Jun 2026REQ-2606-0212Savar Community Medical CentreDonated 16 JunAttended
1 Mar 2026REQ-2603-0057Savar Community Medical CentreDonated 2 MarAttended
24 Feb 2026REQ-2602-0391Mirpur Crescent HospitalCouldn't attend · at work in GazipurCould not attend
19 Nov 2025REQ-2511-0331Mirpur Crescent HospitalDonated 20 NovAttended

Unattended requests stay on the record, with the reason given

On screen

One donor's whole record: seven donations, the 90-day gap drawn as a bar he has cleared, and the one request he couldn't attend left in place, not tidied away.

04

History that protects donors

Anyone inside their recovery window is suppressed automatically. Over-asking is how registers lose people.

A donor inside their recovery window is suppressed from results automatically, with no warning left for someone to miss. Over-asking is how registers lose people (a donor contacted three weeks after donating stops answering), so the register protects them from the coordinator by default. The suppression is visible in the donor's own profile, so nobody wonders why they stopped hearing from it.

What shipped
  • Recovery-window donors suppressed automatically, not flagged
  • Protects donors from over-asking by default
  • Suppression visible on the donor's own profile
Organisations

11 hospitals, clinics and drives on one register · each with its own queue, staff and history

Add organisationThu 17 Sep 2026

Organisations

11 6 hospitals · 3 clinics · 2 drives

Open requests

41 across every queue

Shared register

12,486 donors · 1 copy

Cross-organisation access

None by rule

Every organisation

41 open requests
OrganisationDistrictStaffOpen requests
Savar Community Medical CentreHospitalDhaka67
Mirpur Crescent HospitalHospitalDhaka56
Bayview Clinic, AgrabadClinicChattogram35
Narsunda General HospitalHospitalKishoreganj44
Padma Medical CentreHospitalRajshahi44
Surma Family ClinicClinicSylhet23
Rupsha HospitalHospitalKhulna33
Brahmaputra ClinicClinicMymensingh23
Teesta Medical CentreHospitalRangpur22
Ashulia Garment Workers' DriveDriveDhaka32
Kirtankhola Youth DriveDriveBarishal22

11 organisations41 open

Savar Community Medical Centre · queue

7 open
GroupRequestCallableState
O−REQ-2609-0418Surgery · Today, 3:00 pm8Calling
B+REQ-2609-0415Maternity · Today, 1:30 pm21Donor on the way
A+REQ-2609-0412Medicine · Today, 6:00 pm17Calling
O+REQ-2609-0409Emergency · Today, 4:00 pm26Matching
AB+REQ-2609-0404Paediatrics · 18 Sep, 10:00 am6Scheduled
B−REQ-2609-0398Surgery · 18 Sep, 11:00 am3Calling
A+REQ-2609-0391Medicine · 19 Sep, 9:00 am14Scheduled

What its 6 staff can see

same rule on web and phone
Its own queue, staff and request history
The call lists for its own requests
Another organization's queue or requests
Donors on another organization's call lists
05

Organizations with their own queues

On screen

Eleven hospitals, clinics and drives holding 41 open requests against one shared register, each with its own queue and none able to see another's donors.

Hospitals and drives hold their own requests without the register being forked per organization.

Hospitals and blood drives hold their own request queues inside the one register, with their own staff and their own history, so an organization gets what it needs without the register being forked per organization. Requests are records the register can report on across all of them, which makes national supply visible without an aggregation exercise.

What shipped
  • Per-organization request queues within one register
  • No fork per hospital or drive
  • Cross-organization reporting comes for free
Process

Phase by phase

  1. Phase 1: The Register

    Who, What Type, And Where

    Built the donor record on a real area hierarchy in place of a free-text address, because everything downstream depends on knowing where someone actually is.

    • Donor Register
    • Area Hierarchy
    • Blood Group Model
  2. Phase 2: Matching

    Compatible And Reachable

    Made the match a cross of group compatibility and area, so the list a coordinator opens is ordered by who can help today, not by who is theoretically suitable.

    • Compatibility Rules
    • Area Matching
    • Ranked Results
  3. Phase 3: Two Clients, One Application

    Web And API Side By Side

    Built parallel web and API controllers over the same records, so the coordinators' admin and the donors' phones never disagree about a request's state.

    • Web Admin
    • Mobile API
    • Token Auth
  4. Phase 4: Not Asking Twice

    History That Protects Donors

    Recorded donation history and used it to suppress requests to anyone inside their recovery window, because a register that over-asks is a register people leave.

    • Donation History
    • Eligibility Window
    • Contact Suppression
09:05
NJNusrat JahanSavar · DhakaO−
Resting
75of 90 days

No requests until 2 Oct 2026

Last gave 4 Jul 2026 · Savar Community MC

The register holds requests for 90 days after every donation. Until then you are left off call lists, and coordinators do not see your number.

Your 3 donations

4 Jul 2026Savar Community Medical Centre
18 Mar 2026Savar Community Medical Centre
9 Nov 2025Ashulia Garment Workers' Drive
HomeRequestsHistoryProfile
On screen

A resting donor's own profile: 75 of 90 days since her last donation, no requests until 2 Oct, and the reason shown to her, so she never has to guess.

What it carries now

Group + area

Matching inputs

3

Area levels modelled

2

Clients from one codebase

0

Donors contacted while ineligible

Matching inputs, area levels and clients are descriptions of the system. Donors contacted while ineligible is zero by construction: anyone inside their recovery window is excluded from results instead of being shown with a warning someone might overlook.

Client name withheld under NDA. Figures are approximate, drawn from the engagement’s own reporting.

What it settled

What the architecture settled

A match nobody can attend isn't a match. Reachability belongs in the query, not in the phone call afterward.

A compatible donor who can't attend today isn't a match, and putting reachability in the query, instead of the phone call afterward, is the whole difference.

Free-text addresses make geographic matching impossible, and the cost is paid in the worst hour.

Free-text addresses don't make geographic matching hard; they make it impossible, and the bill arrives in the hour when the register matters most.

Parallel web and API controllers over one set of records is what stops two clients disagreeing.

One set of records behind two clients is what stops a coordinator and a donor seeing different states, which is the failure a second implementation guarantees eventually.

A register that over-asks its donors quietly shrinks, so eligibility windows are a retention feature.

Suppression protects the register itself: donors contacted too soon stop answering, and a shrinking register fails silently long before anyone notices.

How the work was run

The area hierarchy went in before the matching did, because free-text addresses make the whole question unanswerable and everything else depended on fixing that first. Web and API controllers were built in the same pass so the two clients could never drift apart.

Phased with the area hierarchy built and populated before any matching work, since matching on geography requires geography to exist as data. Donation history and the recovery-window suppression were built in the same phase as matching, because a register that over-asks its donors is one that quietly shrinks.

One request, narrowed

From 12,486 names to the 8 who can be at the hospital today

An O negative request at a hospital in Savar, taken apart into the stages the matching query resolves together: the blood group, the area hierarchy, the 90-day window, and travel time. Each stage shows who left the list and why. Switch tabs, or use the arrow keys once one is focused.

O−Savar Community Medical Centre · needed today, 3:00 pm

Candidates left

  1. Registered12,486
  2. O negative612
  3. Dhaka division·
  4. Dhaka district·
  5. Past 90 days·
  6. Callable now·

12,486612match the requested group

The request is for O negative, so the register starts from the donors whose group matches it. Every other group leaves the list before geography is even considered.

  • 612kept: O negative, across all eight divisions
  • −11,874left the list: a different blood group
O+ 3,828B+ 3,562A+ 3,104AB+ 902A− 214B− 188AB− 76

One query, not four passes. Compatibility, area and the 90-day window are resolved together, which is why 0 donors have been contacted while ineligible. The 60-minute reach is illustrative, set on this request.

Architecture

From a request in one queue to a list both clients agree on

One Laravel application instead of a separate API service, because two clients disagreeing about a donor’s state is the failure that matters here. A rule added for one client is enforced for the other by construction.

  1. 01 · Trigger
    Request raised in a queueA hospital, clinic or drive raises it in its own queue inside the one register, so no organization needs a fork of the register.
  2. 02 · Ingestion
    Parallel web and API controllersBlade web controllers and REST API controllers with Sanctum tokens sit side by side over the same models and the same authorization rules.
  3. 03 · Engine
    One matching queryGroup compatibility and the area hierarchy are resolved together, ordered by who can attend, with anyone inside the 90-day window excluded outright.
  4. 04 · State
    The register in MySQLDivision, district and sub-district are related records; donation history sits on each donor; requests are records reportable across every organization.
  5. 05 · Delivery
    Coordinator console and donor phoneBoth clients read the same records, so the admin and the phone can't disagree about a donor's or a request's state.

What the register won't do

Donor safety, privacy & a register that stays true

Nobody inside 90 days can be called

Donation history is recorded, and anyone inside their 90-day window is excluded from results automatically, with no warning for a coordinator to miss. Donors contacted while ineligible: zero, by construction. The suppression is visible on the donor's own profile.

One register, walled queues

Hospitals, clinics and drives each hold their own requests, staff and history inside the one register, and none can see another's donors. Web and API controllers share one authorization layer, so the rule holds identically on the console and the phone.

Places are records, not free text

Donors choose their division, district and sub-district from the hierarchy at registration, so matching queries real places. The console and the phone read one set of records, so a request's state can't differ between them.

Running a register that has to answer in the worst hour? Scope your build in 3 minutes.

Scope your build
Have a project?

Let's talk

Running a large platform, shaping a first MVP, or getting a product ready for a funding round? Tell us where you are. We'll shape the process around it, and stay with you after launch.