Donation management platform for Wellspring Women's Center
A mobile-first, privacy-first digital tool that helps staff and volunteers quickly log donated items, track inventory, record distributions, and generate reports.
| Layer | Technology |
|---|---|
| Framework | Next.js 14 (App Router, TypeScript) |
| Styling | Tailwind CSS + custom design tokens |
| UI Components | Custom components + shadcn/ui |
| Animation | Framer Motion |
| Database | Supabase (PostgreSQL) |
| Auth | Supabase Auth |
| Storage | Supabase Storage (donation photos) |
| Charts | Recharts |
| QR Codes | qrcode.react |
| Forms | React Hook Form + Zod |
| Toasts | Sonner |
| Icons | Lucide React |
| Fonts | DM Serif Display + DM Sans |
| Deploy | Vercel |
wellspring-os/
├── src/
│ ├── app/
│ │ ├── page.tsx # Landing / Welcome page
│ │ ├── layout.tsx # Root layout (fonts, toaster)
│ │ ├── globals.css # Design tokens, component styles
│ │ ├── dashboard/page.tsx # Main dashboard
│ │ ├── donate/page.tsx # Log a donation
│ │ ├── inventory/page.tsx # Browse & filter inventory
│ │ ├── distribute/page.tsx # Record a distribution
│ │ ├── reports/page.tsx # Charts + CSV export
│ │ ├── needs-board/page.tsx # Public needs board
│ │ ├── settings/page.tsx # Admin settings
│ │ └── api/
│ │ ├── donations/route.ts
│ │ ├── distributions/route.ts
│ │ └── reports/route.ts
│ ├── components/
│ │ ├── layout/
│ │ │ ├── TopBar.tsx
│ │ │ └── BottomNav.tsx
│ │ ├── forms/
│ │ │ ├── DonationForm.tsx # Full donation intake form
│ │ │ └── DistributionForm.tsx
│ │ ├── charts/ # (extend with custom Recharts wrappers)
│ │ └── ui/
│ │ ├── AnimatedCounter.tsx
│ │ ├── CategoryBadge.tsx
│ │ └── Badges.tsx
│ ├── lib/
│ │ ├── supabase/
│ │ │ ├── client.ts # Browser Supabase client
│ │ │ └── server.ts # Server Supabase client + admin client
│ │ ├── data.ts # All DB query functions
│ │ ├── constants.ts # Categories, config, thresholds
│ │ └── utils.ts # Helpers (formatDate, exportCSV, etc.)
│ ├── hooks/ # Custom React hooks (add here)
│ └── types/
│ └── index.ts # All TypeScript types
├── supabase/
│ └── migrations/
│ └── 001_initial_schema.sql # Full schema + RLS + views + triggers
├── public/
│ └── manifest.json # PWA manifest
├── .env.local.example
├── next.config.js
├── tailwind.config.js
├── tsconfig.json
└── package.json
git clone <repo>
cd wellspring-os
npm install- Create a project at supabase.com
- Go to SQL Editor → run the contents of
supabase/migrations/001_initial_schema.sql - Go to Storage → create two buckets:
donation-photos(public)item-photos(public)
cp .env.local.example .env.localFill in:
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
Find these in: Supabase Dashboard → Settings → API
npm run dev| Table | Purpose |
|---|---|
profiles |
Extended user data (role: volunteer/staff/admin) |
inventory_items |
Source of truth for all current stock |
donations |
Every incoming donation logged here |
distributions |
Every outgoing distribution — no recipient names ever stored |
needs_board_settings |
Per-category urgency thresholds |
activity_log |
Lightweight audit trail |
- Privacy by design:
distributionstable has NOrecipient_namecolumn. This is intentional and enforced at the schema level, not just the UI. - Auto-inventory: Postgres triggers automatically increment inventory on donation insert and decrement on distribution insert. The app never manually updates
quantity— the trigger handles it. - Status auto-updates: A trigger on
inventory_itemsautomatically setsstatustoavailable/low_stock/out_of_stockwheneverquantitychanges. - RLS (Row Level Security): Volunteers can log donations but cannot read the full distribution list. Staff/admin can see everything. The schema enforces this at the database level.
| View | Purpose |
|---|---|
inventory_summary |
Inventory with donation + distribution counts joined |
category_summary |
Aggregated stats per category |
needs_board |
Urgency levels computed per category |
| Role | Permissions |
|---|---|
volunteer |
Log donations, record distributions, view inventory, see needs board |
staff |
Everything above + read distribution logs + all reports |
admin |
Everything + delete items + edit needs board settings |
To promote a user to staff/admin, update their profiles.role directly in Supabase Dashboard or via a future admin UI.
# Install Vercel CLI
npm i -g vercel
# Deploy
vercel
# Set environment variables in Vercel dashboard or:
vercel env add NEXT_PUBLIC_SUPABASE_URL
vercel env add NEXT_PUBLIC_SUPABASE_ANON_KEY
vercel env add SUPABASE_SERVICE_ROLE_KEY- Fast donation intake form (< 30 seconds)
- Auto-updating live inventory
- Search + filter inventory
- Distribution tracking (privacy-first)
- Low-stock alerts
- Needs Board
- Reports with charts + CSV export
- Role-based views
- QR code per donation batch
- PWA manifest (installable on mobile)
- Supabase Auth login page
- Photo assist (AI category suggestion from uploaded image)
- Printable donation labels (PDF)
- Offline-friendly draft mode (IndexedDB)
- Dark mode
- Email/SMS low-stock alerts
- Donor acknowledgement letters
- Staff-only admin panel for needs board settings
WellspringOS is built for a women's center where recipient privacy is paramount.
- The
distributionstable intentionally has norecipient_nameorrecipient_idcolumn - The UI enforces this — there is no name field on the distribution form
- Notes fields are labeled "situation context only, no names"
- All distribution records show 🔒 anon badge in the UI
- RLS policies prevent volunteers from reading the full distribution log
- Donor names are optional everywhere and default to anonymous
Built for Wellspring Women's Center. For changes, open a pull request with a description of what you changed and why.