Spot-Sync is a robust, high-performance RESTful API service built in Go, designed to manage real-time parking space availability and reservation workflows.
Spot-Sync provides structured management of multiple parking zones (such as standard spaces, EV charging stations, and covered slots), dynamically tracks availability, and processes reservations securely with concurrency protections.
Traditional parking systems frequently suffer from inefficient usage, stale slot data, and booking conflicts (overbooking). Spot-Sync solves these issues by addressing three key real-world challenges:
In busy parking lots, multiple drivers might try to reserve the last remaining parking space at the exact same millisecond. If not handled correctly, this creates a race condition that leads to double-booking.
- The Spot-Sync Solution: During reservation creation, Spot-Sync wraps the capacity check and reservation creation inside a database transaction using an atomic row-level lock (
SELECT ... FOR UPDATEvia GORM) on the target parking zone. This ensures that only one request can read and decrement the capacity at a time, strictly guaranteeing that the total capacity is never breached.
Drivers need to know exactly how many slots are open before driving to a lot, avoiding wasted fuel, emissions, and search time.
- The Spot-Sync Solution: Spot-Sync dynamically calculates the available spots for any parking zone by subtracting the count of active reservations from the zone's total capacity. This calculation is performed efficiently on the database level via a subquery, providing instant, accurate availability figures to drivers.
Not all parking spots are identical, and not all users have the same privileges. EV drivers need EV spots, and lot owners need global visibility.
- The Spot-Sync Solution:
- Zone Segmentation: Supports distinct parking categories—
general,ev_charging, andcovered—each configured with its own hourly pricing and slot count. - Role-Based Access Control (RBAC): Authenticates users via JSON Web Tokens (JWT) and restricts actions according to roles. Drivers can query spots and manage their own bookings. Admins can add zones, define pricing, and audit all reservations across the system.
- Zone Segmentation: Supports distinct parking categories—
- Language: Go (Golang)
- Web Framework: Echo v5 (High-performance, minimalist router)
- ORM: GORM (v2)
- Database: PostgreSQL (Cloud instance via Neon PostgreSQL)
- Authentication: JWT (JSON Web Tokens)
- Validation: Go-Playground Validator v10
- Hot Reloading: Air
- Go (version 1.20 or higher)
- PostgreSQL database (or cloud database connection string)
Create a .env file in the root directory of the project:
PORT=8080
DSN="postgresql://<username>:<password>@<host>/<database>?sslmode=require"
JWT_SECRET="your-super-secure-key"
JWT_EXPIRES_HOURS=24If you have Air installed:
airgo run cmd/main.goThe server will start up on the port specified in your .env file (defaults to 8080), migrate the database tables automatically, and output:
Connected to db
⇨ http server started on [::]:8080
All API endpoints follow a consistent structure. Requests with JSON bodies require the Content-Type: application/json header.
{
"success": true,
"message": "Action completed successfully",
"data": { ... }
}{
"code": 400,
"message": "Brief error summary",
"details": "Technical details or validation failure reasons"
}- URL:
/api/v1/auth/register - Method:
POST - Auth Required: No
- Request Body:
(Note: Valid values for
{ "name": "John Doe", "email": "john@example.com", "password": "securepassword", "role": "driver" }rolearedriveroradmin) - Success Response (201 Created):
{ "success": true, "message": "User registered successfully", "data": { "id": 1, "name": "John Doe", "email": "john@example.com", "role": "driver", "created_at": "2026-06-28T14:00:00Z", "updated_at": "2026-06-28T14:00:00Z" } }
- URL:
/api/v1/auth/login - Method:
POST - Auth Required: No
- Request Body:
{ "email": "john@example.com", "password": "securepassword" } - Success Response (201 Created):
{ "success": true, "message": "Login successfully", "data": { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "user": { "id": 1, "name": "John Doe", "email": "john@example.com", "role": "driver" } } }
- URL:
/api/v1/zones - Method:
POST - Auth Required: Yes (Admin Only)
- Request Body:
(Note: Valid values for
{ "name": "North Sector EV Bay", "type": "ev_charging", "total_capacity": 5, "price_per_hour": 4.50 }typearegeneral,ev_charging, orcovered) - Success Response (201 Created):
{ "success": true, "message": "Zone created successfully", "data": { "id": 1, "name": "North Sector EV Bay", "type": "ev_charging", "total_capacity": 5, "price_per_hour": 4.5, "created_at": "2026-06-28T14:10:00Z" } }
- URL:
/api/v1/zones - Method:
GET - Auth Required: No (Public)
- Success Response (200 OK):
{ "success": true, "message": "Zones retrieved successfully", "data": [ { "id": 1, "name": "North Sector EV Bay", "type": "ev_charging", "total_capacity": 5, "available_spots": 4, "price_per_hour": 4.5, "created_at": "2026-06-28T14:10:00Z" } ] }
- URL:
/api/v1/zones/:id - Method:
GET - Auth Required: No (Public)
- Success Response (200 OK):
{ "success": true, "message": "Zone retrieved successfully", "data": { "id": 1, "name": "North Sector EV Bay", "type": "ev_charging", "total_capacity": 5, "available_spots": 4, "price_per_hour": 4.5, "created_at": "2026-06-28T14:10:00Z" } }
- URL:
/api/v1/reservations - Method:
POST - Auth Required: Yes (Driver & Admin)
- Request Body:
{ "zone_id": 1, "license_plate": "NY-789-AB" } - Success Response (201 Created):
If a zone reaches total capacity, concurrent booking attempts will immediately fail with a
{ "success": true, "message": "Reservation created successfully", "data": { "id": 12, "user_id": 2, "zone_id": 1, "license_plate": "NY-789-AB", "status": "active", "created_at": "2026-06-28T14:15:00Z", "updated_at": "2026-06-28T14:15:00Z" } }400 Bad Requestor500 Internal Server Errordetailing that theparking zone is completely full.
- URL:
/api/v1/reservations/my-reservations - Method:
GET - Auth Required: Yes (Driver & Admin)
- Success Response (200 OK):
{ "success": true, "message": "My reservations retrieved successfully", "data": [ { "id": 12, "license_plate": "NY-789-AB", "status": "active", "created_at": "2026-06-28T14:15:00Z", "zone": { "id": 1, "name": "North Sector EV Bay", "type": "ev_charging" } } ] }
- URL:
/api/v1/reservations/:id - Method:
DELETE - Auth Required: Yes (Reservation Owner or Admin only)
- Success Response (200 OK):
{ "success": true, "message": "Reservation cancelled successfully", "data": null }
- URL:
/api/v1/reservations - Method:
GET - Auth Required: Yes (Admin Only)
- Success Response (200 OK):
{ "success": true, "message": "Reservations retrieved successfully", "data": [ { "id": 12, "user_id": 2, "zone_id": 1, "license_plate": "NY-789-AB", "status": "active", "created_at": "2026-06-28T14:15:00Z", "zone": { "id": 1, "name": "North Sector EV Bay", "type": "ev_charging" } } ] }
Follow this sequence to test all features of the application locally from your command line.
First, create the users. One will act as the manager/admin and the other as the customer/driver.
# Register Admin
curl -X POST http://localhost:8080/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"name": "Admin User", "email": "admin@spotsync.com", "password": "AdminSecurePassword", "role": "admin"}'
# Register Driver
curl -X POST http://localhost:8080/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"name": "Driver Sam", "email": "sam@driver.com", "password": "SamSecurePassword", "role": "driver"}'Perform login requests to obtain the JWT bearer tokens.
# Login as Admin (Save the token from the response)
curl -X POST http://localhost:8080/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "admin@spotsync.com", "password": "AdminSecurePassword"}'
# Login as Driver (Save the token from the response)
curl -X POST http://localhost:8080/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "sam@driver.com", "password": "SamSecurePassword"}'Note: For the subsequent authenticated commands, replace <ADMIN_TOKEN> and <DRIVER_TOKEN> with the token string returned under "data" -> "token".
Using the Admin token, create a parking zone. Let's make one with a total capacity of 2.
curl -X POST http://localhost:8080/api/v1/zones \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <ADMIN_TOKEN>" \
-d '{"name": "Downtown EV Station", "type": "ev_charging", "total_capacity": 2, "price_per_hour": 6.00}'Request the list of zones to verify the zone is created and has 2 available spots.
curl -X GET http://localhost:8080/api/v1/zonesMake a booking in the newly created zone (assuming the zone ID is 1).
curl -X POST http://localhost:8080/api/v1/reservations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <DRIVER_TOKEN>" \
-d '{"zone_id": 1, "license_plate": "EV-COOL-2"}'Get the details for the specific zone to see that the available_spots value has decreased to 1.
curl -X GET http://localhost:8080/api/v1/zones/1Inspect bookings as a driver and audit all bookings as an admin.
# Get logged-in driver's personal list
curl -X GET http://localhost:8080/api/v1/reservations/my-reservations \
-H "Authorization: Bearer <DRIVER_TOKEN>"
# Audit all system bookings (Admin only)
curl -X GET http://localhost:8080/api/v1/reservations \
-H "Authorization: Bearer <ADMIN_TOKEN>"Cancel the booking to free up space in the lot (assuming the reservation ID is 1).
curl -X DELETE http://localhost:8080/api/v1/reservations/1 \
-H "Authorization: Bearer <DRIVER_TOKEN>"Verify via GET /api/v1/zones/1 that availability has returned to 2 spots.