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. Nothing is mocked or sped up: every click is a real session against a real Appwrite backend.
The closed loop — claim → submit proof → NGO approves → badge lands
The whole product in one take. A volunteer claims a task and submits their work, the NGO reviews that submission and approves it, and the badge lands in the volunteer's vault. It all happens on-platform, without the handoff to email that a directory would leave you to. The sign-out in the middle is real: the volunteer and the org are two different accounts.
NGO badge tooling — define a badge, then read the analytics
Badges are org-owned definitions rather than a hardcoded list: an NGO picks a template or builds its own, and the awarder mints it on claim approval.
Run
bun run demoto regenerate: it reseeds, records fresh MP4s, and converts them to GIFs. The reseed is not optional. Demo tasks auto-archive after 30 days of no activity, and the closed-loop recording needs its claim and badge state reset or the badge never appears. See CONTRIBUTING.md for the one-time setup,e2e/demo/for the 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/micro-match.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 (459 tests across server / API / components)
bun run test:e2e # Playwright (run `bunx playwright install chromium` once)
bun run seed # (re)seed the demo NGO + tasks — run before any demo recording
bun run demo # seed, record the demo suite, convert to GIFs
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/.
The demo suite in e2e/demo/ is deliberately not part of this. It shares Playwright but exists to record the GIFs above, so it's slow by design (slowMo, dwell beats), needs seeded fixtures, and never runs in CI.
Stored in Appwrite TablesDB (see docs/appwrite-schema.md for full schema details):
| 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. To automatically provision the database tables, attributes, and storage buckets:
bun scripts/setup-appwrite.ts- 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 — full API specification (public & authenticated endpoints)
- docs/appwrite-schema.md — database schema and Appwrite resources specification
- docs/faq.md — FAQ
MIT — see LICENSE.





