A web-based equipment loan management system for organizations. Browse inventory, request loans, and manage returns with automated email notifications.
- Browse equipment catalog with search and filtering
- Request loans with flexible date ranges
- Automated email notifications for loan reminders and updates
- Admin dashboard for managing inventory, locations, and loan approvals
- Multi-user support with role-based permissions (Admin, User, Kiosk)
- Support for normal and temporary items
- Organized inventory with categories, locations, and boxes
- Browse available equipment in the catalog
- Request a loan by selecting dates and items
- Receive email confirmation when admin approves
- Get automated weekly reminders for active loans
- Return items and view loan history
- Manage equipment catalog (add, edit, remove items)
- Organize items by categories, locations, and boxes
- Review and approve/reject loan requests
- Track all active and past loans
- Manage user accounts and permissions
- Self-service stations for quick item checkout and returns
- Simplified interface for public access points
- Next.js 16 (Pages Router) — React framework
- React 18 with TypeScript (strict)
- Prisma 7 — Database ORM
- PostgreSQL — Database
- NextAuth.js — Authentication
- Tailwind CSS 3 — Utility-first styling
- shadcn/ui — Component primitives (owned in
components/ui/) - Radix UI — Unstyled accessible primitives (Dialog, Dropdown, Switch, Tooltip, Label)
- next-themes — Dark mode (class-based)
- sonner — Toast notifications
- react-select — Creatable/multi selects (shadcn-styled wrapper)
- lucide-react + react-icons — Icons
- SWR — Client-side data fetching
- AWS SES — Email notifications
- All UI primitives live in
components/ui/— they're source files you own and edit freely (shadcn pattern, not an installed library). - Design tokens are CSS variables in
styles/globals.css. Colors map to HSL vars (--primary,--background,--card,--destructive,--success,--warning, etc.) with.darkoverrides. - Tailwind config in
tailwind.config.tsexposes those tokens viabg-primary,text-muted-foreground, etc. Dark mode is class-based — toggled bynext-themesvia theclassattribute on<html>. - Toasts use
sonner. Importtoastfromsonnerand calltoast.success(...),toast.error(...),toast.warning(...). - Creatable selects use the
CreatableSelectwrapper incomponents/ui/creatable-select.tsx— it stylesreact-select's creatable via theclassNamesAPI so it respects dark mode and tokens without runtime theme juggling.
- Install dependencies:
pnpm install- Set up environment variables:
cp .env.example .env- Start local database:
docker-compose up -d- Run migrations and seed data:
pnpm prisma migrate dev
pnpm prisma db seed- Start development server (also boots the local SES mock automatically):
pnpm devVisit http://localhost:3000.
pnpm dev— Next dev server + local SES mockpnpm build—prisma migrate deploy+next buildpnpm start— Production serverpnpm type-check—tsc --noEmitpnpm lint— ESLint (Next config)pnpm test— Vitest against a disposable Postgres (docker-compose)pnpm test:ci— Vitest without docker (expectsDATABASE_URLalready set)
The dev script starts aws-ses-v2-local in parallel. All emails are captured instead of being sent.
Open the email viewer at http://localhost:8005 to see sent emails.
Schema is defined in prisma/schema.prisma. After schema changes:
pnpm prisma migrate dev --name description_of_changeGenerate test data:
pnpm prisma db seedSupports Google OAuth and username/password authentication via NextAuth.js. Configure providers in the NextAuth API route.
User Roles:
- Admin: Full access to manage catalog, users, and loans
- User: Browse catalog, request loans, view own history
- Kiosk: Simplified interface for self-service stations
Admins can elevate a kiosk session to ADMIN temporarily via a 4-digit PIN (set in /admin). The elevated session auto-expires after 30 minutes.
Klapi is deployed automatically when a new commit lands on main.
DATABASE_URL: PostgreSQL connection stringNEXTAUTH_SECRET: Random secret for NextAuth (generate withopenssl rand -base64 32)NEXTAUTH_URL: Public URL of your deploymentGOOGLE_CLIENT_ID,GOOGLE_CLIENT_SECRET: Google OAuth credentialsAWS_REGION,AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY: AWS SES for emailsEMAIL_FROM: Sender email address
pages/ Next.js Pages Router — routes, API handlers, SSR via getServerSideProps
components/ App-specific React components
components/ui/ shadcn/ui primitives (owned source, edit freely)
contexts/ React contexts (cart, dates)
hooks/ Custom hooks
lib/utils.ts `cn()` className merger
styles/globals.css Tailwind base + CSS token variables (light/dark)
tailwind.config.ts Tailwind config (content paths, token mapping, dark mode)
utils/ Server and shared helpers (Prisma client, loan helpers, etc.)
prisma/ Schema, migrations, seed