Leaflet is a community-first library for lending and borrowing books. Think of it as a neighbourhood shelf that lives online: anyone can request to join, admins keep the catalogue tidy, and super admins make sure the rules stay fair. The frontend is a Vite-powered React single-page app, and Supabase handles authentication, databases, and realtime updates.
- Welcome & Purpose
- Guided Project Tour
- Plain-Language Setup
- Everyday App Workflow
- How Data Flows Through Leaflet
- Code Map in Plain English
- Why We Built It This Way
- Tools, Commands & Scripts
- Quality Checks, Deployment & Next Steps
- Further Resources
We built Leaflet to solve a simple problem: neighbours and co-workers own interesting books that sit unread. Leaflet keeps track of who owns what, who wants to borrow it, and how those loans progress. The project balances three audiences:
- Members who just want to join, browse, and borrow.
- Admins who approve new members and keep the catalogue organised.
- Super admins who can rescue any account or policy if something breaks.
This README explains the entire workflow in plain language so anyone—technical or not—can stand up the app, understand its moving parts, and maintain it with confidence.
- Frontend shell: A React SPA (Single Page Application) created with Vite for fast local development. Routing lives in
src/App.jsx, and we lean on Material UI for layout and components. - State management: Three main React Contexts keep the UI in sync:
AuthContexttracks who is logged in.UserContextloads the member profile, approval status, loans, and saved books.BookContextfetches book lists, keeps filters applied, and listens for realtime updates.
- Supabase backend: Supabase Auth manages signups/login, Postgres stores books and profiles, Storage keeps avatars, and the realtime channel notifies the UI when books change.
- Services layer: Every call to Supabase is wrapped in a service (e.g.,
src/services/bookService.js). UI components never talk to Supabase directly; they go through these functions for consistent permissions and error handling. - Admin tools: The admin dashboard (under
/admin) shows approval queues, catalogue health, active loans, and user management. Admins can promote, demote, or archive content without leaving the dashboard.
If you would rather watch it run than read code, follow the setup instructions below and click through the app—the routing, modals, and flows mirror what you see described here.
Setting up Leaflet takes about 20 minutes. You only need basic computer skills: copying text, pasting keys, and running simple commands.
- Node.js 18 or newer: download from nodejs.org. Installing Node also installs
npm, the package manager we use. - A Supabase account: sign up at supabase.com with any email address.
- Git (optional but helpful): lets you download updates and contribute back.
- Log in to Supabase and click New project.
- Give it a name (for example “leaflet-dev”).
- Choose the Free plan and any region close to you.
- Set a database password you will remember.
- Once the project finishes provisioning, open Settings → API. You will need:
- the Project URL (looks like
https://your-project.supabase.co) - the anon public key
- the Project URL (looks like
- In Authentication → URL Configuration add
http://localhost:5173to the redirect URLs so Supabase lets you sign in during local development. - In Authentication → Policies create (or note) the email allowlist you want. By default Leaflet accepts
@sprinklr.comor@gmail.comemails; you can change this later in code undersrc/constants/constants.js.
-
In the project root, duplicate
.env.sampleif it exists or create a new.envfile. -
Add the Supabase values you collected:
VITE_SUPABASE_URL=https://<your-project>.supabase.co VITE_SUPABASE_ANON_KEY=<your-public-anon-key> SUPABASE_SUPER_ADMIN_EMAIL=<email-that-should-start-as-super-admin>
-
If you want to export schema snapshots or run SQL migrations from your machine, also add the database connection string (find it under Settings → Database → Connection String):
SUPABASE_DB_URL=postgresql://postgres:<your-password>@<host>:5432/postgresThis optional value lets scripts in
supabase_schema/connect securely.
Tip: Environment variables stay on your computer. Do not share
.envor commit it to Git.
Open a terminal (or Command Prompt on Windows), change into the project folder, and run:
npm installThis downloads the React, Supabase, and tooling packages listed in package.json.
npm run devVisit http://localhost:5173 in your browser. The Vite dev server live-reloads whenever you edit files. Use the Signup form to create a new account with an allowed email domain. Your first signup should use the SUPABASE_SUPER_ADMIN_EMAIL so you have full control.
- Signup: A visitor enters an approved email and password. Supabase Auth creates the account but marks it as
pendingapproval. - Email confirmation: Supabase sends a confirmation email. After clicking the link, the user can log in but still sees a “Pending Approval” screen.
- Profile setup: Once approved, the member fills out their name, preferred contact info, and optionally uploads an avatar. The profile lives in the
profilestable. - Browse & request: Members explore the catalogue (books pulled from
booksandcatalogtables). They can save favourites, request to borrow, and track requests from the dashboard. - Borrow & return: When a lender accepts a request, a loan record is created. The borrower can see due dates; the lender marks the book returned.
- Open the Admin Dashboard (
/admin). - Review the Approval Queue: approve or reject pending users.
- Check Books for duplicates or archived items and tidy as needed.
- Monitor Requests and Loans for anything stuck or overdue.
- Use User Management to promote helpful members to admins or demote inactive admins back to regular users.
- Can do everything an admin does plus:
- Update any user’s role instantly.
- Export schema snapshots via
npm run getSchemato audit policies. - Apply emergency SQL fixes by editing
supabase_schema/update.sqland runningnpm run updateDB.
- Should regularly check that RLS (Row Level Security) policies still align with the same role rules our automation uses (documented for Codex in
AGENTS.md).
AuthContext(src/contexts/AuthContext.jsx) listens to Supabase Auth. It keeps the current session in state and exposes simple helpers likesignup,login, andlogout.- Email domains are validated before any request leaves the browser using
ALLOWED_EMAIL_DOMAINS(src/constants/constants.js). This prevents unwanted signups. useSessionTracker(src/hooks/useSessionTracker.js) subscribes to Supabase session events so the UI updates instantly when someone logs in or out.
- After Auth signs a member in,
UserContext(src/contexts/UserContext.jsx) fetches their profile viagetUserProfile(src/services/profileService.js). - Approval status lives on the profile record.
UserContextexposesisApproved,isPendingApproval, androleso components know when to gate screens. - The route guards (
PrivateRoute.jsxandAdminRoute.jsx) rely on those flags to redirect members who are still pending or who lack admin rights. - Role changes flow only through services inside
src/services/adminService.js. Admins and super admins trigger these functions from the dashboard tables.
BookContextloads all relevant book data usinggetBooks,getSavedBooks, andgetBookWithRelationsfromsrc/services. It also exposes helpers to archive, delete, or save a book and to send borrow requests.- When a member requests a book,
requestBorrowBook(src/services/bookRequestService.js) writes a record tobook_requests. The response updates both the main list and the saved-books view to keep the UI consistent. - Approving a request creates a loan via
bookLoanService.js. The borrower sees due dates in their dashboard; the lender (or an admin) can mark the loan as returned. - Shared helpers in
src/utilities(for examplevalidateAndSubmitBookForm.js) keep validation and form submission logic away from components so features stay easy to maintain.
subscribeToBookChanges(src/services/realtimeService.js) opens a Supabase realtime channel forbooksand related tables.- When Supabase broadcasts an insert, update, or delete,
BookContextrefreshes the local list or performs a focused fetch (addBookById) so viewers see changes without refreshing. - Window-level custom events (e.g.,
'books:added') ensure optimistic UI updates when the current member adds a book.
├── src/
│ ├── App.jsx # Routes and layout wiring
│ ├── main.jsx # React entry point
│ ├── components/
│ │ ├── common/ # Shared UI pieces like loaders and route guards
│ │ └── providers/ # Error boundaries and Snackbar context
│ ├── contexts/ # Auth, User, Book providers plus their hooks
│ ├── features/ # Screens grouped by domain (auth, books, admin…)
│ ├── hooks/ # Reusable hooks (session tracking, debouncing)
│ ├── services/ # Supabase access layer (one file per domain)
│ ├── theme/ # Material UI theme helpers
│ └── utilities/ # Pure helper functions and validations
├── supabase_schema/ # SQL helper + JSON snapshots of database metadata
├── scripts/ # Node scripts for schema exports and migrations
├── structure.txt # Plain-text outline kept in sync with the repo
└── AGENTS.md # Automation instructions for Codex (not a human guide)
Keep structure.txt aligned with any structural change so new contributors can rely on it as a quick map.
- Separation of concerns: UI components stay lean because data fetching and mutations live in services. This reduces the risk of bypassing security policies.
- Context-driven state: React Contexts supply the minimal data each screen needs—sessions, profiles, books—without dragging in global state libraries.
- Supabase-first backend: Supabase combines authentication, database, file storage, and realtime messaging with generous free tiers, making it ideal for community projects.
- Role-based access control: Roles (
user,admin,super_admin) match the operating rules maintained for Codex inAGENTS.md, and RLS policies insupabase_schema/update.sqlmirror the same structure so database access stays consistent. - Testable utilities: Form validation, auth flows, and other logic sit in
src/utilitieswith dedicated tests. This keeps regressions low when requirements change.
| Command | What it does and why it matters |
|---|---|
npm run dev |
Starts the Vite dev server at http://localhost:5173 with live reloads. |
npm run build |
Creates an optimised production bundle (useful before deploying to Vercel or similar). |
npm run preview |
Serves the built bundle locally to mimic production. |
npm run lint |
Runs ESLint with project rules; fixes style issues early. |
npm run test |
Executes Vitest suites for hooks, utilities, and contexts. |
npm run test:watch |
Runs tests continuously while you develop. |
npm run getSchema |
Pulls Supabase metadata into JSON snapshots (needs SUPABASE_DB_URL). |
npm run updateDB |
Applies supabase_schema/update.sql, refreshes metadata, then clears the SQL file for safety. |
When introducing new tooling or scripts, document them here and in package.json comments so the team stays aligned.
- Before pushing changes run
npm run lintandnpm test. Both should pass without warnings. - Database changes belong in
supabase_schema/update.sql. After editing, runnpm run getSchemato refresh the JSON snapshots and commit them together. - Deployments: supply
.envvalues to your hosting provider (for example Vercel) and runnpm run buildto verify the production bundle. Ensure Supabase policies in your hosted project match the checked-in SQL. - Monitoring: Super admins should periodically export the schema to confirm RLS still protects sensitive data. Admins should review the approval queue daily so newcomers are not blocked.
Suggested follow-up tasks once you are comfortable:
- Tailor the email allowlist in
src/constants/constants.jsto match your community. - Add onboarding content or welcome emails for newly approved users.
- Expand test coverage around any new approval or loan workflows you introduce.
AGENTS.md— automation notes used by Codex (humans can stick with this README).structure.txt— current repository layout, updated with every structural change.- Supabase Docs — guides for auth, database policies, and storage.
- Material UI and Framer Motion — component and animation systems used in the UI.
Built with care for communities that read. 📚🌿