A micro-volunteering marketplace pairing NGOs with volunteers for bite-sized, skill-building tasks. Volunteers browse a feed of 5-30 minute missions, claim what fits their skills, and earn badges for approved work. NGOs post tasks, review submissions, and build a verified presence on the platform.
- Bite-sized task feed — filter by
≤15 / ≤20 / ≤30 min, hashtag, or sort by shortest first. - Volunteer side — claim tasks, submit proof (link or upload), track status, earn badges, level up.
- NGO side — post tasks with deadline + max-volunteers caps, review submissions, manage org-owned badge definitions.
- NGO verification — soft-gate trust system. NGOs submit a tax/charity ID, admins review with ProPublica lookup enrichment, approval back-fills the Verified chip on every existing task.
- Custom badge definitions — NGOs define their own awards (label, color, icon, criteria); the engine auto-awards on claim approval.
- Role mobility — users can flip between Volunteer and NGO; downgrading from NGO triggers a clean transactional teardown of verification + tasks.
- Auto-translate — task title + description translate to the viewer's language via Microsoft Azure Translator.
- Email notifications — verification approve/reject sends Mailgun-backed transactional emails to the NGO.
These are real Playwright recordings of the app — captured by the test suite at e2e/demo/, post-processed to GIF for embedding here.
Run
bun run demoto regenerate (record fresh MP4s + convert to GIFs). Seee2e/demo/for the demo specs andplaywright.demo.config.tsfor the recording configuration.
The core loop, end-to-end:
sequenceDiagram
autonumber
actor V as Volunteer
actor N as NGO
participant App as MicroMatch
participant DB as Appwrite
participant Mail as Mailgun
N->>App: Post task
App->>DB: tasks.create (isVerified ← NGO's verification status)
V->>App: Browse feed, claim task
App->>DB: claims.create (status=pending)
V->>App: Submit proof (URL or file)
App->>DB: claims.update (proofUrl, notes)
N->>App: Approve claim
App->>DB: claims.update (status=approved)
App->>DB: badges.create (matching BadgeDefinitions for org)
App-->>V: Dashboard updates, badge appears in vault
Note over N,Mail: Verification flow (parallel)
N->>App: Submit verification (tax ID + doc)
App->>DB: ngoVerifications.create (status=pending)
Note over App: Admin reviews queue with ProPublica enrichment
App->>DB: status=approved, back-fill tasks.isVerified
App->>Mail: Send "you're verified" email
Mail-->>N: 📧
| Framework | SvelteKit on Vercel (adapter-vercel, nodejs22.x runtime) |
| Runtime + package manager | Bun |
| Backend | Appwrite Cloud — Database (TablesDB), Auth, Storage, Teams |
| Mailgun (HTTP API, no SDK dep) | |
| NGO verification | ProPublica Nonprofit Explorer API for US 501(c)(3) lookups |
| i18n | Azure Translator |
| UI | Plus Jakarta Sans + Inter, custom CSS (warm cream palette + coral accents), Iconify, Lottie |
| Testing | Vitest (unit + API + components) and Playwright (e2e) |
Quick path:
git clone https://github.com/Builder106/MicroMatch.git
cd MicroMatch
bun install
cp .env.example .env
# Fill in Appwrite + Mailgun + ProPublica keys
bun run devThe app runs at http://localhost:5173. Full setup (Appwrite resources, environment variables, project layout, conventions) lives in CONTRIBUTING.md.
bun run dev # dev server with HMR
bun run build # production build (uses adapter-vercel)
bun run check # svelte-check + tsc
bun run test # vitest (123 tests across server / API / components)
bun run test:e2e # Playwright (run `bunx playwright install chromium` once)
bun run render-media # regenerate the README banners + social preview from /static/*.htmlThree layers of coverage:
- Server modules (vitest, node) — pure-ish helpers and DB CRUD:
tagColors,propublica,email,verifications,badgeDefs,badgeCriteria,badgeAwarder. Mock fetch + Appwrite at the module boundary. - API endpoints (vitest, node) —
/api/verifications,/api/verifications/[userId]/approve,/api/verifications/[userId]/reject,/api/profile/role,/api/badges/manage. Auth gates, validation, multi-step side effects. - Components (vitest, jsdom) —
BadgeChip,EmptyState,ProgressBar,VerificationCard(all four state branches via mocked fetch). - End-to-end (Playwright, chromium) — public-facing flows: landing, feed, login/signup multi-step, forgot-password, protected route redirect.
bun run test:coverage writes an HTML report to coverage/.
Stored in Appwrite TablesDB:
| Table | Holds |
|---|---|
tasks |
Mission cards posted by NGOs (title, tags, time estimate, deadline, status, isVerified) |
claims |
Volunteer submissions for tasks (proofUrl, notes, status: pending / approved / rejected) |
badges |
Awarded badge instances (userId, taskId, label, color) |
badgeDefinitions |
Org-owned badge templates (orgId, label, criteria, taskId for task-specific) |
ngoVerifications |
Verification queue (orgName, country, taxId, docFileId, status, reason) |
Plus three Appwrite Teams (volunteers, ngos, admins) for role + moderation gating. Storage is one bucket with file-level permissions for both avatars and verification docs.
- CONTRIBUTING.md — local setup, project layout, conventions, PR process
- docs/index.md — platform docs index
- docs/volunteer.md — volunteer guide
- docs/ngo.md — NGO guide
- docs/api.md — public API reference
- docs/faq.md — FAQ
MIT — see LICENSE.


