Share more, buy less.
StuffLibrary.org is an open-source platform that helps neighbors share under-used items safely and easily. Think: ladders, lawnmowers, camping gear—things we all own but rarely use. By treating neighborhoods as collective libraries, we can save money, reduce waste, and strengthen community ties.
To make it natural and safe for neighbors to borrow and lend things, following principles of trust, accountability, and care.
- Safety first – people and property are protected by design.
- Civic utility – the platform recedes into the background like a public library or Craigslist.
- Generosity – small acts of care and reciprocity build long-term trust.
- MVP: user accounts, neighborhood groups, item listings, borrow/return flow.
- Trust & Safety: verification, reputation, condition tracking.
- Community: acknowledgments, lightweight messaging, neighborhood stats.
- Future: verticalized libraries (e.g. LensLibrary), deposits, insurance pools.
- Node.js 18+ and npm
- Git
# Clone the repository
git clone https://github.com/mcull/stufflibrary.git
cd stufflibrary
# Install dependencies
npm install
# Set up environment variables
cp .env.example .env.local
# Edit .env.local with your actual values (see Environment Setup below)
# Start the development server
npm run devOpen http://localhost:3000 to see the application.
-
Copy the example environment file:
cp .env.example .env.local
-
Edit
.env.localwith your actual values:- Database: Add your Supabase
DATABASE_URL - Cache: Add your Redis
REDIS_URL - AI: Add your
OPENAI_API_KEY - Storage: Configure Wasabi S3 credentials
- App: Set
NEXT_PUBLIC_APP_URLto your domain
- Database: Add your Supabase
-
Important: Never commit
.env.localor any file containing secrets
# Option 1: Using npm
npm run dev
# Option 2: Using make
make devSetup:
npm install/make install- Install dependenciesmake setup- Full setup (install + db push)make clean- Clean build artifacts
Development:
npm run dev/make dev- Start dev server with Turbopacknpm run build/make build- Build for productionnpm start/make start- Start production server
Code Quality:
npm run lint/make lint- Lint code with ESLintnpm run format/make format- Format code with Prettiernpm run typecheck/make typecheck- Type check with TypeScriptmake check- Run all quality checks
Testing:
npm test/make test- Run unit testsnpm run test:unit/make test-unit- Run unit testsnpm run test:e2e/make test-e2e- Run E2E tests (when available)
Database:
npm run db:push/make db-push- Push schema to databasenpm run db:studio/make db-studio- Open Prisma Studionpm run seed/make seed- Seed database (when available)
Run make help to see all available commands.
All environment variables are documented in .env.example with examples and descriptions. Key variables include:
DATABASE_URL- Database connection stringREDIS_URL- Cache connection stringOPENAI_API_KEY- AI service authenticationWASABI_*- File storage configurationNEXT_PUBLIC_APP_URL- Public app URL for client-side usage
- Connect your GitHub repository to Vercel
- Configure environment variables in Vercel dashboard:
- Go to Project Settings → Environment Variables
- Add all variables from
.env.examplewith production values - Ensure
NEXT_PUBLIC_APP_URLmatches your domain
- Deploy automatically triggers on push to main branch
npm run dev- Start development server with Turbopacknpm run build- Build for productionnpm run start- Start production servernpm run lint- Run ESLintnpm run lint:fix- Run ESLint with auto-fixnpm run format- Format code with Prettiernpm run format:check- Check code formattingnpm run typecheck- Run TypeScript type checkingnpm run test- Run tests in watch modenpm run test:ci- Run tests with coverage (CI mode)npm run db:generate- Generate Prisma clientnpm run db:push- Push schema to databasenpm run db:migrate- Run database migrationsnpm run db:studio- Open Prisma Studio
- Use Camera: Capture an item photo for automatic recognition and watercolor rendering. Works best when the item is in front of you.
- Describe Instead: Provide a name, brand, and details to receive three safe watercolor illustrations generated from licensed references or de-identified AI renderings—no digging items out of storage required.
- Framework: Next.js 15 with App Router
- Language: TypeScript (strict mode)
- Database: Supabase (PostgreSQL) + Prisma ORM
- Styling: Material-UI (MUI) + Tailwind CSS
- Code Quality: ESLint, Prettier, Husky git hooks
- Testing: Jest + React Testing Library
- CI/CD: GitHub Actions
- Deployment: Vercel
- Environment: Zod validation for type-safe configuration
This is an open-source project. Contributions, ideas, and forks are welcome. \n
This project supports notifying contributors after code is deployed by parsing closed issues from merged PRs and emailing the original submitter (without exposing their email address).
Endpoints
POST /api/webhooks/vercel-deploy- Compares the previous deployed commit to the current one, finds merged PRs with closing keywords (close/fix/resolve #n), fetches the issues, extracts an anonymized SLFB slug from each issue body, and emails the contributor via Resend.
POST /api/webhooks/feedback-resolved- Directly emails the contributor for a single issue number (useful for manual tests or ad hoc notifications).
Auth (Vercel-compatible)
- Either of the following is accepted:
Authorization: Bearer $WEBHOOK_SECRETx-vercel-signature: <HMAC-SHA1 of raw body using WEBHOOK_SECRET>
Environment Variables
WEBHOOK_SECRET: shared secret used by Vercel to sign payloads (and for Bearer for manual tests)GITHUB_TOKEN: repo read access for comparing commits and fetching issue bodiesRESEND_API_KEY: for email deliveryFEEDBACK_SLUG_SECRET: signs/verifies anonymized reporter slugs in issue bodies
Vercel Setup
- Add an Outgoing Webhook → Event: Deployment Ready (Production). URL:
https://<your-domain>/api/webhooks/vercel-deploy. Secret:WEBHOOK_SECRET. - Ensure the environment variables above are set for the Production environment.
- First deploy per environment seeds the
DeployMarkerand does not send emails. Subsequent deploys send notifications for issues closed by merged PRs in the deployed range.
Curl Examples (after deploying)
Using Vercel signature (recommended)
export WEBHOOK_SECRET=... # your Vercel webhook secret
# feedback-resolved (manual single-issue test)
BODY='{"issueNumber":277}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha1 -hmac "$WEBHOOK_SECRET" -binary | xxd -p -c 256)
curl -X POST https://<your-domain>/api/webhooks/feedback-resolved \
-H "x-vercel-signature: $SIG" \
-H "Content-Type: application/json" \
--data-binary "$BODY"
# vercel-deploy (manual test with a real deployed commit SHA)
BODY='{"deployment":{"meta":{"githubCommitSha":"GIT_SHA"},"target":"production"}}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha1 -hmac "$WEBHOOK_SECRET" -binary | xxd -p -c 256)
curl -X POST https://<your-domain>/api/webhooks/vercel-deploy \
-H "x-vercel-signature: $SIG" \
-H "Content-Type: application/json" \
--data-binary "$BODY"
Using Bearer (convenient for manual tests)
curl -X POST https://<your-domain>/api/webhooks/feedback-resolved \
-H "Authorization: Bearer $WEBHOOK_SECRET" \
-H "Content-Type: application/json" \
-d '{"issueNumber":277}'
Notes
- The anonymized reporter slug in issue bodies has the form
SLFB:v1:<userId>:<sig8>. The signature is verified server-side withFEEDBACK_SLUG_SECRET. - If you rotate
FEEDBACK_SLUG_SECRET, slugs created with the old secret will no longer validate.
Helper scripts
- Generate a slug:
FEEDBACK_SLUG_SECRET=... npm run gen:slug -- <userId> - Verify a slug:
FEEDBACK_SLUG_SECRET=... npm run verify:slug -- <slug>