尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證medicard67-spec/nfc-medicard
翻譯準備中
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
A secure clinical data portal built to accompany the NFC MediCard FYP report. Three role-based
portals (Patient, Doctor, Admin) built on:檢視完整 README ↗A secure clinical data portal built to accompany the NFC MediCard FYP report. Three role-based portals (Patient, Doctor, Admin) built on:
.github/workflows/ci.yml).| Video | What it shows |
|---|---|
| Overview (1:30) | What NFC MediCard is and how it works, in one compilation |
| Patient demo (1:32) | A patient's journey: card registration, check-in, the doctor's tap, and the patient app |
| Doctor walkthrough (1:18) | Dashboard, appointments, admissions and discharge, medication renewals, labs and imaging, referrals, and the tablet + USB reader |
| Admin walkthrough (1:12) | Hospital dashboard, adding patients and assigning cards, check-in queue and rooms, doctor accounts, data entry, reports, and the audit log |
supabase/schema.sql,
and run it. This creates all the tables (profiles, patients, doctors,
medical_history, lab_results, radiology, messages, appointments, vitals,
audit_log) with Row Level Security enabled and no client-facing policies — all access goes
through the backend's service-role key.
supabase/migration_002_audit_and_unread.sql
instead to pick up the new audit_log table and the messages.read column.npm run seed are still pre-confirmed regardless of this setting, so seeding and
local testing aren't affected either way.
Storage buckets (lab-results, radiology) are created automatically the first time the backend
starts — no manual setup needed.
cd server && cp .env.example .env
Edit server/.env and fill in SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY.
cd ../client && cp .env.example .env
Edit client/.env and fill in VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY (the anon key,
not the service role key).
cd server && npm install
cd ../client && npm install
From /server, with your .env filled in:
npm run seed
This creates demo accounts and sample clinical data directly in your Supabase project. Demo logins
(password for all: password123):
| Role | Notes | |
|---|---|---|
| Admin | [email protected] | |
| Doctor | [email protected] | Dr. Sarah Jenkins — Cardiology |
| Doctor | [email protected] | Dr. Robert Chan — Endocrinology |
| Patient | [email protected] | Card UID: 0443FADB3D0289 |
| Patient | [email protected] | Card UID: 07D8E9F0 |
Terminal 1 — Backend (from /server):
npm run dev
Runs on http://localhost:4001.
Terminal 2 — Frontend (from /client):
npm run dev
Runs on http://localhost:5173. Log in with any of the demo accounts above.
0443FADB3D0289 to pull up the seeded patient's full record.AABBCCDD) to register a brand-new
patient and bind it to that "card".jspdf)./api/doctor/stats.From /server:
npm test
Runs the Vitest + Supertest suite (auth middleware, patient CRUD, NFC lookup) against a mocked Supabase client — no real database or network access needed. The same command runs automatically on every push/PR via GitHub Actions.
nfc-medicard/
├── .github/workflows/ci.yml # Runs backend tests + frontend build on push/PR
├── docs/videos/ # Overview, patient demo, doctor and admin walkthroughs
├── supabase/
│ ├── schema.sql # Full schema + RLS (fresh setup)
│ └── migration_002_audit_and_unread.sql # Incremental migration (existing projects)
├── server/ # Express API (Supabase service-role client)
│ ├── test/ # Vitest + Supertest suite, mocked Supabase client
│ └── src/
│ ├── routes/ # patients, medical-history, lab-results, radiology,
│ │ # messages, nfc, appointments, admin, doctor, audit, users
│ ├── middleware/auth.js # verifies Supabase JWTs
│ ├── lib/ # supabase client, storage upload helper, audit log helper
│ └── seed.js
└── client/ # React app
└── src/
├── pages/{patient,doctor,admin}/
├── components/{MonthCalendar,QrCodeCard,QrScannerView}.jsx
├── context/{AuthContext,ThemeContext,ToastContext,UnreadContext}.jsx
└── lib/{supabase.js,api.js,webNfc.js,exportPdf.js}
All data access goes through the Express backend, which uses the Supabase service role key
(bypasses Row Level Security). The frontend only ever holds the anon key, used solely for
Supabase Auth (sign-in), and calls the backend with the resulting access token in the
Authorization: Bearer <token> header. The backend's own middleware (requireAuth /
requireRole) enforces who can see and modify what. Key mutating actions (registrations, NFC
scans, record/lab/imaging additions) are recorded to audit_log for accountability.
This deploys the frontend to Vercel (free) and the backend to Render (free tier), both connected to a GitHub repo so every push auto-deploys.
git init # if not already a repo
git add .
git commit -m "Initial commit"
Create a new empty repository on github.com/new, then:
git remote add origin <your-repo-url>
git branch -M main
git push -u origin main
server.npm install, start command npm start (or let Render auto-detect from
package.json).SUPABASE_URLSUPABASE_SERVICE_ROLE_KEYCLIENT_ORIGIN — set this after step 2 below, to your Vercel URL (comma-separate if you add
more origins later, e.g. https://app.vercel.app,https://yourdomain.com)PORT automatically — no need to add it.https://<something>.onrender.com URL — that's your VITE_API_URL base for the frontend
(append /api).client.npm run build, output dist
(defaults are correct).VITE_SUPABASE_URLVITE_SUPABASE_ANON_KEYVITE_API_URL — https://<your-render-app>.onrender.com/apihttps://<something>.vercel.app URL.Go back to Render and set CLIENT_ORIGIN to the Vercel URL from step 2 (this is what CORS checks
against), then redeploy the backend service so the change takes effect.
Your site is now live at the Vercel URL — share that with anyone to let them use the app.
The same React codebase can be wrapped into a native Android app with
Capacitor — no rewrite, no separate mobile codebase. The website keeps
working exactly as before; this just adds an installable .apk on top. (iOS isn't covered here —
building an iOS app requires Xcode, which only runs on macOS.)
Already set up in this repo:
client/capacitor.config.json — app id com.medicard.nfc, web dir dist.client/.env.production — overrides VITE_API_URL to point at the deployed Render backend
(instead of localhost) whenever npm run build runs, so the packaged app talks to production.client/android/ — the generated native Android project (gitignored: .gradle/, build/,
local.properties, and any local JDK under .tools/).cd client
npm run build # bundles the app with the production API URL baked in
npx cap sync android # copies the fresh web build into the native project
Then open the client/android folder in Android Studio, let Gradle sync, and go to
Build → Build Bundle(s) / APK(s) → Build APK(s). The resulting .apk can be sideloaded
directly onto any Android device — no Play Store submission needed.
Capacitor's Android WebView serves the app from the origin https://localhost. Add that to the
backend's CLIENT_ORIGIN environment variable on Render (comma-separated alongside the Vercel
URL) so the packaged app's API calls aren't rejected by CORS:
https://nfc-medicard-5y8u.vercel.app,https://localhost
For presenting somewhere with unreliable or no internet, there's a fully self-contained offline build — no Supabase, no Render, no Vercel, nothing outside your own laptop:
cd client && npm run build:offline # builds client/dist-offline against a local API
cd ../server && npm run offline # serves the app + a canned in-memory dataset on one port
Open http://localhost:4444 — same demo accounts as above ([email protected],
[email protected], [email protected] / password123, card UID 0443FADB3D0289). You can
disconnect Wi-Fi entirely and it keeps working: server/offline-server.js is a single Express
process serving both the built frontend and an in-memory stand-in for the API, seeded with the
same demo data as npm run seed. It's for a local demo only — the auth "token" it issues has no
real security, so never deploy this file or expose it beyond your own machine.
supabase.storage.from(bucket).createSignedUrl()).