A state-of-the-art, feature-rich, and secure Full-Stack Urban Parking Management System. Designed to solve modern urban parking availability, search, and reservation challenges, Parkfinder provides an interactive, role-based platform for Users and Administrators. Built using high-performance technologies like React 19, Vite, TypeScript, Tailwind CSS v4, and Express.js.
π Live Demo: parkfinder-three.vercel.app
- π Key Features
- π οΈ Tech Stack & Ecosystem
- π Application Workflow
- βοΈ Local Setup Guide
- οΏ½ Security & Environment Variables
- οΏ½π Project Directory Structure
- βοΈ Deploy on Render / Vercel
- π€ Contributing (SSOC '26)
- β Show Your Support
- π€ Author
Parkfinder provides a tailored experience with role-based access for drivers and parking administrators.
- Secure JWT Authentication: Tokens stored securely in context memory for session persistence.
- Role-Based Access Control (RBAC): Distinct permissions for standard Users and system Admins.
- Security Standards: Hashed user passwords using Bcrypt / BcryptJS, route protection middlewares, and CORS origin controls.
- Password Recovery: Complete secure email workflow for Forgot/Reset passwords utilizing Nodemailer.
- Environment-Based Secrets: JWT and admin secrets managed through secure environment variables (no hardcoded keys).
- Dual Layout Grid: Seamless toggle between interactive Map (Leaflet) and list card formats.
- Live Filtering: Sort parking lots instantly based on location, price, rating, safety level, covered status, and slot availability.
- Proximity Calculation: Displays approximate distances from central locations to make booking decisions easier.
- Dynamic Slot Counter: Real-time decrement of available slots as new bookings are committed.
- Log Management: Vehicle Entry & Exit tracking to log vehicle location logs and elapsed durations.
- Immediate Receipts: Instant reservation confirmations containing invoice amounts.
- User Dashboard: Real-time tracker for total bookings, active parking logs, spent history, and recent logs.
- Interactive Visualizations: Clean Recharts graphs displaying analytics summaries.
- Database Oversight: Superuser dashboard controls to create, modify, and delete parking locations.
- User Management: Monitor list logs of registered drivers, manage login credentials, and handle role assignments.
- System Diagnostics: Detailed tables showing system metrics and vehicle entry/exit history.
- PDF Ticket Exports: Client-side ticket printing module converting HTML elements into PDF downloads via
jsPDFandhtml2canvas.
- Library: React 19 & TypeScript
- Build Tool: Vite
- Styling: Tailwind CSS v4 & custom CSS modules
- Routing: React Router v7 (includes protected client-side routes)
- Map Integrations: Leaflet & React Leaflet
- Data Visualizations: Recharts & Chart.js
- Asset Management: Lucide React (sleek modern icons)
- Animations: Framer Motion (smooth state transitions)
- PDF Exporter:
jsPDF&html2canvas
- Runtime: Node.js
- Framework: Express.js v5 (highly performing router)
- Database: MongoDB via Mongoose (ODM)
- Encryption: JSON Web Tokens (JWT) & BcryptJS
- Notifications: Nodemailer (SMTP configs for transactional mails)
The diagram below represents how different components of the Parkfinder architecture communicate:
flowchart TD
subgraph Client ["Client-Side (React 19 SPA)"]
User["User / Admin Client"] --> Frontend["React / Vite SPA"]
Frontend --> Context["Auth Context"]
Frontend --> Views["Map / Dashboard / Slots"]
end
subgraph Network ["Network Layer"]
Views -- "HTTP requests with JWT" --> Axios["Axios Instance"]
end
subgraph Server ["Backend Server (Express.js)"]
Axios --> Express["Express Server & Routes"]
Express --> AuthM["Auth Middleware Guard"]
AuthM --> Controllers["Controllers (Auth, Booking, Admin)"]
end
subgraph Data ["Database & Utilities"]
Controllers --> DB[("MongoDB (Mongoose)")]
Controllers --> Mailer["Nodemailer SMTP Service"]
end
classDef client fill:#0b3c5d,stroke:#328cc1,stroke-width:2px,color:#fff;
classDef server fill:#1d2731,stroke:#f9d5bb,stroke-width:2px,color:#fff;
classDef database fill:#05386b,stroke:#5cdb95,stroke-width:2px,color:#fff;
class User,Frontend,Context,Views client;
class Express,AuthM,Controllers server;
class DB,Mailer database;
Below is the standard sequence of actions for user registration and booking reservation:
sequenceDiagram
autonumber
actor Driver as Driver (UI)
participant Client as React Client
participant Server as Express Server
participant DB as MongoDB
Driver->>Client: Open Explorer & Select Slot
Client->>Server: POST /api/bookings (JWT + Body)
Note over Server: Run Auth Middleware & verify JWT
Server->>DB: Check availability & create booking
DB-->>Server: Saved booking record
Server->>DB: Decrement Parking.availableSlots
Server-->>Client: Booking success response
Client-->>Driver: Renders confirmation & enables PDF download ticket
Follow these steps to run a copy of the project locally on your machine.
- Node.js (v18.x or above recommended)
- MongoDB (Local instance or MongoDB Atlas cluster URI)
- NPM or Yarn
-
Navigate to the backend server directory:
cd server -
Install the backend dependencies:
npm install
-
Create your local environment configuration file: Create a
.envfile in theserver/directory and paste the following configurations:# Required - Security Configuration JWT_SECRET=your-secure-random-jwt-secret-key-min-32-chars ADMIN_SECRET=your-secure-admin-secret-key-min-32-chars # Server Configuration PORT=5000 # Database Configuration MONGO_URI=mongodb://127.0.0.1:27017/parkfinder # Frontend Configuration FRONTEND_URL=http://localhost:5173 # Email/SMTP Configuration SMTP_HOST=smtp.gmail.com SMTP_PORT=587 SMTP_USER=example@gmail.com SMTP_PASS=your_smtp_app_password SMTP_SECURE=false EMAIL_FROM=no-reply@parkfinder.com
β οΈ IMPORTANT SECURITY NOTES:- NEVER commit the
.envfile to version control - Use strong, random strings for
JWT_SECRETandADMIN_SECRET(minimum 32 characters) - Generate secure secrets using:
openssl rand -base64 32 - A
.env.examplefile is provided as a template for reference
- NEVER commit the
-
Seed the database with default parking slot records:
node seed.js
-
Start the Express development server:
npm run dev
The API will start running on
http://localhost:5000
- Open a new terminal window/tab and navigate to the client directory:
cd client - Install the frontend dependencies:
npm install
- Create your frontend environment configuration file:
Inside
client/.env:VITE_API_URL=http://localhost:5000
- Start the React/Vite development server:
The client app will compile and start running on
npm run dev
http://localhost:5173
ParkFinder requires secure environment variables for JWT token signing and admin account protection. These should never be hardcoded in your application.
| Variable | Purpose | Generation |
|---|---|---|
JWT_SECRET |
Sign and verify JWT authentication tokens | openssl rand -base64 32 |
ADMIN_SECRET |
Validate admin account creation requests | openssl rand -base64 32 |
-
Create
.envfile in theserver/directory:cp .env.example .env
-
Generate secure secrets:
# On Mac/Linux openssl rand -base64 32 # Use output for JWT_SECRET openssl rand -base64 32 # Use output for ADMIN_SECRET
-
Update
.envwith generated values:JWT_SECRET=<your-generated-secret-here> ADMIN_SECRET=<your-generated-secret-here>
-
Verify
.envis NOT tracked by Git:# Already included in .gitignore (do not remove) echo ".env" >> .gitignore
-
Start the server - It will validate environment variables at startup:
npm run dev
If variables are missing, you'll see:
β FATAL ERROR: Missing required environment variables: JWT_SECRET, ADMIN_SECRET Please set these in your .env file or system environment.
When deploying to Render, Vercel, or similar platforms:
- Do NOT commit
.envto version control - Set environment variables through the platform's dashboard:
- Render: Settings β Environment β Environment Variables
- Vercel: Settings β Environment Variables
- The application validates these at startup and will fail gracefully with a clear error message if missing
For more security details, see SECURITY.md.
Parkfinder utilizes Redis as a centralized, server-side caching layer to significantly reduce database load and improve response times for read-heavy operations, such as parking slot searches and dashboard queries.
Prerequisites: You need a running Redis instance.
- Local: Install Redis via Homebrew (
brew install redis), Docker (docker run -d -p 6379:6379 redis), or download the Windows port. - Cloud: Use a managed Redis service like Upstash or Redis Enterprise.
Environment Variable:
Add your Redis connection string to the .env file in the server/ directory:
REDIS_URL=redis://localhost:6379- Middleware Approach: Caching is implemented as an Express middleware (
server/utils/cache.js) that intercepts requests. If a cache hit occurs, it responds immediately; otherwise, it passes the request to the database and caches the outgoing response. - Key Generation: Cache keys are generated deterministically using the requested URL path and query parameters.
Example Key:
cache:/api/slots?location=Downtown&isEV=true
Different endpoints demand different caching strategies. The TTL is configurable per route by passing options to the middleware:
// Caches response for 60 seconds
router.get("/", cacheMiddleware({ ttl: 60 }), getParkingSlots);- Frequent Updates: (e.g., slot searches) use a short TTL like
60seconds. - Static Data: (e.g., general analytics) can use a longer TTL.
To prevent serving stale data, the cache is automatically invalidated whenever a resource is mutated (created, updated, or deleted):
- An Admin creates, updates, or deletes a parking slot.
- The database updates the document.
- The controller calls
clearCache()to purge all cached results globally (matchingcache:*). - The next user request fetches fresh data and repopulates the Redis cache.
The system is designed with a graceful fallback. If the Redis service crashes or becomes temporarily unavailable, the middleware catches the error and silently falls back to direct database queries without affecting application availability or user experience.
To add caching to a new read-heavy endpoint:
- Import
cacheMiddlewarefrom../utils/cache.js. - Insert it before your controller function in the route definition.
- Define an appropriate
ttlin seconds:cacheMiddleware({ ttl: 120 }). - Ensure any controller modifying this data calls
clearCache()to invalidate it.
Parkfinder features a robust and modular automated integration testing suite built with Vitest and Supertest to validate critical backend API endpoints (such as Authentication and Bookings) ensuring reliability and preventing regressions.
- Vitest: The primary testing framework offering extremely fast, isolated test execution environments. Configured globally via
server/vitest.config.js. - Supertest: Simulates HTTP requests against the Express application in memory without starting the physical server port.
- MongoDB Memory Server: To maintain determinism and test isolation, a fresh, in-memory MongoDB instance is spun up via
server/test/setup.js. This guarantees that tests do not mutate production or local development databases.
The tests run completely independently. Environment variables are statically overridden via Vitest (NODE_ENV=test, JWT_SECRET, ADMIN_SECRET), and Redis/Database connections are stubbed to prevent conflicts.
To run the tests, simply execute the following command in the server directory:
npm run testWhen creating tests for a new endpoint (e.g., server/test/newFeature.integration.test.js):
- Import the Server Application:
import request from 'supertest'; import app from '../server.js';
- Utilize
describeanditblocks to organize your tests by route and behavior. - Seed Data in
beforeAll: If your endpoints require an authenticated user or specific database items, create them once in thebeforeAllhook. - Assert Appropriately: Verify HTTP status codes (
expect(res.status).toBe(200)), response payload structures, and success/error messages.
- Do not share state between tests: Each
itblock should ideally run independently. UsebeforeEachto reset specific state if necessary. - Teardown Collections: The
setup.jsfile automatically cleans up collections usingafterEachhooks (await collections[key].deleteMany()) so data does not bleed across tests. - Isolate External Services: Do not hit third-party APIs (e.g., payment gateways, emails). Use tools like
vi.mock()or simply ensure the test environment bypasses real external executions.
To ensure data integrity and prevent malformed payloads from reaching the controllers, Parkfinder utilizes a centralized request validation layer powered by Zod.
- Middleware: A generic validation middleware (
server/middleware/validate.js) intercepts requests before they hit the controller. - Strict Verification: The middleware parses the incoming
req.body,req.query, andreq.paramsagainst the provided Zod schema. If validation passes, the request is allowed through and properties are sanitized. If it fails, a structured HTTP 400 response is generated. - Separation of Concerns: Controllers are kept clean and focused strictly on business logic rather than checking for missing parameters or malformed data types.
All validation schemas are modularly organized within the server/validators/ directory based on the specific feature:
auth.validator.js: Schemas for user registration, login, and password resets.booking.validator.js: Schemas for creating, updating, and cancelling reservations.slot.validator.js: Schemas for admin slot modifications and creation.
When validation fails, the API standardizes the response to an HTTP 400 Bad Request, structured as follows:
{
"success": false,
"message": "Validation failed",
"errors": [
{
"field": "body.email",
"message": "Invalid email address"
},
{
"field": "body.password",
"message": "Password must be at least 6 characters"
}
]
}To apply validation to a new route, follow these guidelines:
- Define a Schema: Create a new schema in the appropriate
server/validators/*.jsfile.export const updateProfileSchema = z.object({ body: z.object({ name: z.string().min(2, 'Name is required').optional(), }), });
- Apply the Middleware: Import
validateRequestand your schema in the route definition.import { validateRequest } from '../middleware/validate.js'; import { updateProfileSchema } from '../validators/user.validator.js'; router.put('/profile', authMiddleware, validateRequest(updateProfileSchema), updateProfile);
- Use Passthrough For Agnostic Payloads: When a schema should accept unpredictable additional properties, utilize
.passthrough()on your Zod object.
Here's an overview of how the repository is structured:
parkfinder/
βββ .github/ # Github workflows, templates and guidelines
β βββ CODE_OF_CONDUCT.md
β βββ CONTRIBUTING.md
βββ client/ # Frontend client workspace
β βββ public/ # Static assets directory
β βββ src/
β β βββ assets/ # Images and design layouts
β β βββ components/ # Reusable views (Navbar, Maps, Dashboard, AdminPanel)
β β βββ context/ # AuthContext provider
β β βββ pages/ # Routing views (Login, Signup, Reset)
β β βββ App.tsx # Main routing hub
β β βββ main.tsx # DOM mounting script
β βββ package.json
β βββ tsconfig.json
βββ server/ # Backend API server workspace
β βββ controllers/ # Controller endpoints (auth, bookings, dashboards)
β βββ database/ # Database setup configuration
β βββ getData/ # Feed seed routes helper
β βββ middleware/ # Validation and security middleware
β βββ models/ # Mongoose schema definitions (User, Booking, Parking, Logs)
β βββ routes/ # REST routing paths
β βββ utils/ # Helper modules (email configurations)
β βββ seed.js # Database seeding script
β βββ server.js # Application starting point
β βββ package.json
βββ package.json # Test suite configuration
βββ README.md # Project documentation
The application is structured to support easy deployment on cloud platforms:
The client directory can be deployed directly to platforms like Vercel or Netlify:
- Set the root directory to
client. - Use Build Command:
npm run build - Set Publish directory to
dist. - Configure environment variable
VITE_API_URLpointing to your deployed backend URL.
The server directory can be deployed as a Web Service to platforms like Render:
- Set the root directory to
server. - Build Command:
npm install - Start Command:
npm start - Define environment variables (
MONGO_URI,PORT,JWT_SECRET, etc.) in the dashboard configuration settings.
This project is proud to be part of the Social Summer of Code 2026 (SSoC26)! We highly encourage contributions to improve the system's features, accessibility, and security.
- Fork the Repository.
- Create your Feature Branch:
git checkout -b feature/awesome-feature - Commit your changes with descriptive messages:
git commit -m 'feat: add slot reservation scheduler' - Push to your branch:
git push origin feature/awesome-feature - Create a Pull Request targeting the
mainbranch.
Please review our Contributing Guidelines and Code of Conduct for more details.
If you find this project helpful or educational, please consider giving it a star! β It helps the project gain more visibility and motivates contributors.
- Anchal Singh - Full Stack Developer
Made with β€οΈ for modern urban parking