Blood donor discovery and emergency response web app — donor search, SOS requests and blood bank stock in one place.
Runs in any mobile browser, installs to the home screen, and the shell still opens without a network connection. No Play Store install required.
Live: https://lifedrop-app.devsodage-7.workers.dev
| Feature | Details |
|---|---|
| Donor search | Blood group, city, eligibility and verified filters, with sorting |
| Compatibility | Blood group compatibility matrix with a quick picker |
| 90-day cooldown | Tracks the 90-day gap since the last donation, with ready / cooldown badges |
| SOS requests | Patient, hospital, units and urgency in a live feed; resolve or delete |
| Blood bank stock | Group-wise stock for 4 hospitals, editable by admins only |
| Donor registration | Name, phone, blood group, age, weight, city and last donation date |
| My profile | Signed-in donors can view, update or delete their own profile |
| Contact reveal | Public view shows only the last four digits; signed-in users can request the full number (logged and rate limited) |
| Admin console | Verify donors, update stock, load or remove demo data |
| PWA | Home screen install on Android and iPhone, offline shell |
- Frontend: plain HTML, CSS and JavaScript — no build step, no framework
- Backend: Supabase — Postgres, Auth, Row Level Security and RPC functions
- Hosting: Cloudflare Workers (static assets)
- Auth: email and password via Supabase, email confirmation disabled
lifedrop/
├─ index.html
├─ css/app.css
├─ js/
│ ├─ config.js ← Supabase URL and anon key
│ ├─ cloud.js ← REST/RPC store (auth, donors, SOS, stock)
│ ├─ auth.js ← sign in / sign up modal
│ └─ app.js ← UI logic
├─ icons/icon.svg
├─ manifest.webmanifest
├─ sw.js
├─ _headers
├─ wrangler.jsonc
├─ serve.py
└─ supabase/
├─ schema.sql ← full database (tables, RLS, RPC, seed data)
└─ fix-grants.sql ← table-level grants and insert guard
- No client can
SELECTfrom thedonorstable directly — neither anonymous nor authenticated users. - Public search reads the
donors_publicview, which exposes only the last four digits of the phone number (phone_hint). - The full number is available only through the
donor_contact(p_id)RPC, and only to a signed-in user. - Every reveal is written to
contact_eventsand limited to 25 reveals per hour. - A user cannot mark their own record as
verified— insert and update triggers enforce this. - Admin access requires
profiles.role = 'admin'.
- Create a project in Supabase, open the SQL Editor and run the full
supabase/schema.sql. - Run
supabase/fix-grants.sqlas well. - In Authentication → Providers → Email, disable Confirm email (or set
mailer_autoconfirm: truethrough the Management API). - Add the project URL and anon key to
js/config.js:
cloud: {
enabled: true,
url: 'https://<ref>.supabase.co',
anonKey: '<anon key>',
}Never place the
service_rolekey in the frontend.
- Sign up in the app with the admin email address (a profile is created automatically).
- In the Supabase SQL Editor:
update profiles set role = 'admin' where email = 'you@example.com';- Reload the app — the Admin console appears.
python serve.py # http://localhost:5174wrangler deployLive URL: https://lifedrop-app.devsodage-7.workers.dev
Bump the
CACHEversion insw.jswhenever app files change, so clients do not keep serving the old cache.
| Table | Purpose |
|---|---|
profiles |
One row per authenticated user, with role (donor or admin) |
donors |
Full donor records, with the phone number kept private |
donors_public (view) |
Phone-free projection used by public search |
sos_requests |
Emergency blood requests |
hospitals |
Blood banks |
inventory |
Units per bank and blood group |
contact_events |
Audit trail of number reveals, used for rate limiting |
- ✅ Cloud backend connected (auth, donors, SOS, stock, audit)
- ✅ RLS, masking and rate limiting verified
- ✅ Live on Cloudflare Workers
- ✅ PWA manifest and offline shell
- ⬜ Custom domain (add routes in
wrangler.jsoncif required)
Built by Devraj Arun Sodage.