Skip to content

njiedev/b4pdatabase

Repository files navigation

B4P Medical Supplies Database

An inventory management system for tracking, organizing, and managing the lifecycle of donated medical supplies. Built for a nonprofit's warehouse operations team to replace ad-hoc spreadsheets with a single source of truth that tracks expiration, location, donation status, and audit history across thousands of SKUs.

Live: https://b4pdatabase.vercel.app


Overview

The application provides authenticated, role-aware access to a medical supplies catalog with rich metadata (lot numbers, expiration dates, pallet locations, packaging hierarchy, cost basis, and supplier links). Operators can search, filter, edit, archive, and mark items as donated; admins manage user access through a dedicated admin console.

Key features

  • Inventory CRUD with strongly-typed fields covering supply type, lot number, expiration, pallet location, packaging hierarchy (units → unit boxes → cardboard boxes → pallets), per-unit cost, weight, and dimensions.
  • Lifecycle tabs — active inventory, archived items, and donated items are separated into discrete views so the working set stays focused.
  • Expiration tracking with automatic flagging and filterable status (expired / not expired / all).
  • Search and filtering by free-text query and supply type.
  • Authentication via Supabase Auth (email/password) with rate-limit handling and session persistence.
  • Role-based access control — protected routes gate the dashboard, and an admin-only console manages users.
  • Responsive UI built on shadcn/ui + Radix primitives with light/dark theme support.
  • Toast notifications for every mutation so destructive actions are visible and reversible.

Tech stack

Layer Choice Why
Framework React 18 + Vite 6 Fast HMR, modern build pipeline, minimal config
Language TypeScript (strict) Compile-time guarantees on a data-heavy schema
Styling Tailwind CSS v4 Utility-first, zero-runtime, consistent design tokens
Components shadcn/ui + Radix UI Accessible primitives, owned source, no vendor lock-in
Routing React Router v7 Nested routes with layout providers
Forms react-hook-form + Zod Schema-first validation, minimal re-renders
Backend Supabase (Postgres + Auth + RLS) Managed Postgres with row-level security and JWT auth
Notifications Sonner Lightweight toast system
Hosting Vercel Zero-config deploys with preview URLs per branch

Architecture

src/
├── pages/              # Route-level views (Auth, MedicalSupplies, AdminUsers, 404)
├── components/
│   ├── layout/         # Shell, navigation, theme toggle
│   ├── ui/             # shadcn primitives (button, dialog, table, ...)
│   └── login-form.tsx
├── context/
│   └── SessionContext.tsx   # Auth state + Supabase session subscription
├── router/
│   ├── index.tsx              # Route definitions
│   └── AuthProtectedRoute.tsx # Redirect guard for authenticated routes
├── supabase/index.ts   # Typed Supabase client singleton
├── hooks/              # Reusable hooks (theme, mobile, etc.)
├── lib/                # Utilities (cn, formatters)
├── config.ts           # Env var validation (fails fast on missing config)
└── Providers.tsx       # Top-level providers (theme, session, toaster)

Design decisions

  • Single source of truth for session state. SessionContext subscribes to supabase.auth.onAuthStateChange once at the provider level so every consumer reads from one stream — no duplicate listeners, no race conditions on logout.
  • Fail-fast configuration. config.ts throws synchronously at module load if Supabase env vars are missing, surfacing misconfiguration during boot rather than at the first network call.
  • Server-side authorization. Auth is enforced in Supabase via row-level security policies. The client guard (AuthProtectedRoute) is a UX convenience — it redirects unauthenticated users — not the security boundary.
  • Tab-based lifecycle separation. Active / archived / donated items are filtered server-side and rendered in distinct tabs, keeping payloads small and the active working set unambiguous.

Getting started

Prerequisites

Setup

git clone https://github.com/njiedev/b4pdatabase.git
cd b4pdatabase
npm install

Create a .env file in the project root:

VITE_SUPABASE_URL=https://<your-project>.supabase.co
VITE_SUPABASE_ANON_KEY=<your-anon-key>

Both variables are required — the app will refuse to boot without them.

Scripts

Command Description
npm run dev Start the Vite dev server with HMR
npm run build Type-check (tsc) then produce a production bundle
npm run preview Serve the production build locally
npm run lint Lint with ESLint (zero warnings allowed)

Supabase schema

The application expects a medical_supplies table and a profiles table (for admin role flags). RLS policies should restrict reads/writes to authenticated users, with admin-only policies on the profiles table for user management. See src/pages/MedicalSuppliesPage.tsx for the canonical field shape.


Deployment

The app is deployed on Vercel. vercel.json configures SPA fallback routing so client-side routes resolve correctly on hard refresh. Pushes to main deploy to production; every other branch produces a preview URL.

Required Vercel environment variables:

  • VITE_SUPABASE_URL
  • VITE_SUPABASE_ANON_KEY

Roadmap

  • Image uploads per SKU (Supabase Storage)
  • Excel / CSV import + export
  • Custom domain
  • Barcode scanning for pallet check-in
  • Invite-only registration

See to do.md for the working list.


License

MIT — see LICENSE.MD.

About

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors