Statio Core is an MVP parking lot management system with a Spring Boot backend and a Vite + React + TypeScript frontend. The focus is on functionality: user authentication (JWT), searching & reserving parking spots, checking in/out, session billing, and admin tools for user and activity log management.
This repository contains the full-stack scaffold with Docker support and local development scripts.
Live URL here:
https://statio.tonys-dev.com/
-
Frontend
- React 19 (Vite + TypeScript)
- TailwindCSS
- shadcn/ui (Radix + Tailwind components)
- Axios (HTTP client)
- @tanstack/react-query (server state)
- Zustand (auth state)
- react-router-dom (routing)
-
Backend
- Spring Boot 3.5.8 (Java 17)
- Spring Security with JWT
- Spring Data JPA + Flyway
- PostgreSQL 15
- Micrometer + Prometheus + Grafana for observability
- Caffeine for local caching (Spring Cache abstraction)
-
Dev / Tooling
- Gradle (wrapper included) for backend
- Vite + npm for frontend
- Docker / docker-compose for full-stack local deployment
Root layout (important files and folders):
/ (repo root)
ββ backend/ # Spring Boot application (Gradle)
β ββ src/main/resources/application.yml
β ββ Dockerfile
β ββ build.gradle
ββ frontend/ # Vite + React + TypeScript frontend
β ββ package.json
β ββ src/
ββ docs/ # API docs, DB schema
β ββ API_Documentation.md
β ββ DATABASE_SCHEMA.sql
ββ docker-compose.yml # Compose file for local full-stack
ββ scripts/ # dev helper scripts
ββ README.md # <- you are here
Refer to the frontend/README.md and backend/README.md for module-level details.
- Node.js >= 18 (for Vite + frontend)
- npm (or yarn/pnpm) β the repo uses npm scripts by default
- Java 17 (toolchain used by Gradle wrapper) β Gradle wrapper will download matching distribution
- Docker & Docker Compose (for containerized setup)
- PostgreSQL (if running backend without Docker)
The repository expects environment variables for database and JWT configuration. When using Docker Compose the .env file (in repo root) is referenced by docker-compose.yml.
Create a .env file in the project root (example below):
# Database (local / docker)
DB_NAME=statiocore_db
DB_USER=statiocore_user
DB_PASSWORD=change_me
DB_PORT=5432
# JWT
JWT_SECRET=changeme_supersecret_key
JWT_EXPIRATION=3600000
# Production (optional)
DATABASE_URL=jdbc:postgresql://<host>:5432/<db>
# Spring profile (for docker compose)
SPRING_PROFILES_ACTIVE=docker.env keys referenced in code/config:
- DB_NAME, DB_USER, DB_PASSWORD, DB_PORT
- JWT_SECRET, JWT_EXPIRATION
- DATABASE_URL (production profile)
Note: For local development with the backend run via Gradle, application.yml uses the local profile and expects DB connection to localhost:${DB_PORT}. The docker-compose service maps host port 5433 to the container's 5432 by default (see docker-compose.yml).
The easiest way to run Statio Core is using the provided setup and run scripts:
chmod +x scripts/setup.sh scripts/run.sh
./scripts/setup.sh # First time only - sets up Docker and .env
./scripts/run.sh # Starts all servicesSet-ExecutionPolicy RemoteSigned -Scope CurrentUser # First time only
.\scripts\setup.ps1 # Sets up Docker and .env
.\scripts\run.ps1 # Starts all servicesThe scripts will:
- β Detect your OS and Docker installation
- β Help install Docker if needed
- β
Create
.envfrom.env.example - β Build and start all containers (Frontend, Backend, DB, Prometheus, Grafana)
- β Show you the URLs to access each service
See scripts/README.md for detailed documentation.
If you prefer manual setup, follow these steps:
A) Full-stack (recommended, Docker):
- Create a
.envfile in the project root (see example above). - Start the stack:
# from repo root
docker compose up --build- Services (default ports):
- Backend (Spring Boot): http://localhost:8080
- Prometheus: http://localhost:9090
- Grafana: http://localhost:3000
- PostgreSQL (host port): 5433 (container port 5432) β mapped in docker-compose.yml
B) Run frontend + backend locally (no Docker):
- Start backend using Gradle wrapper
# from repo root
cd backend
./gradlew bootRun- Start frontend
cd frontend
npm install
npm run devFrontend Vite dev server default: http://localhost:5173
Frontend (inside frontend/):
npm install
npm run dev # start Vite dev server
npm run build # build production bundle
npm run preview # preview built bundle
npm run lint # run ESLintBackend (inside backend/):
./gradlew bootRun # run the Spring Boot app
./gradlew build # build jar
./gradlew test # run testsDocker Compose (repo root):
docker compose up --build
docker compose downDev helper scripts (see scripts/dev/):
scripts/dev/start.shβ wraps a docker compose dev flow (may reference docker-compose.dev.yml)
- The backend exposes
/api/auth/loginand/api/auth/registerendpoints. - On successful login/register the backend returns an
AuthResponsewith a JWT token and user object. - The frontend stores the JWT in
sessionStorageand user data in a Zustand store (frontend/src/store/authStore.ts). - Security: Role information is always extracted from the JWT token (not from sessionStorage) to prevent privilege escalation attacks.
- Protected routes are implemented via
ProtectedRouteand the React Router layout redirects users by role to/user/*or/admin/*.
Statio Core includes comprehensive API documentation using Swagger/OpenAPI 3.0. All endpoints are documented with:
- Request/response schemas
- Authentication requirements
- Parameter descriptions
- Example values
- Error responses
When the backend is running, access the interactive API documentation at:
π http://localhost:8080/swagger-ui/index.html
The documentation is organized into three main sections:
-
Authentication API (
/api/auth)- User registration
- User login
- JWT token generation
-
User API (
/api/user)- Dashboard and statistics
- Available parking spots
- Reservations management
- Parking session check-in/out
- Payment history
-
Admin API (
/api/admin)- System dashboard
- Building, Floor, and Spot management (CRUD)
- User account management
- Activity logs and audit trail
To test protected endpoints in Swagger UI:
- Login via
/api/auth/loginendpoint - Copy the JWT token from the response
- Click the "Authorize" button at the top
- Enter:
Bearer {your-token-here} - Click "Authorize" and close the dialog
- Now all protected endpoints will include your token
Raw OpenAPI specification available at:
- JSON:
http://localhost:8080/v3/api-docs - YAML:
http://localhost:8080/v3/api-docs.yaml
Use these URLs to import the API into tools like Postman, Insomnia, or generate client SDKs.
This project includes observability features via Spring Boot Actuator, Micrometer, Prometheus and Grafana. When running via the provided docker-compose.yml the stack includes Prometheus and Grafana services.
Actuator endpoints (backend)
- Base actuator path:
http://localhost:8080/actuator(when enabled) - Useful endpoints:
- GET
/actuator/healthβ basic health status - GET
/actuator/metricsβ available metrics list - GET
/actuator/metrics/{metric.name}β fetch specific metric (e.g.http.server.requests,jvm.memory.used) - GET
/actuator/prometheusβ Prometheus scrape endpoint (Micrometer export) - GET
/actuator/cachesβ list caches managed by Spring Cache (exposed whenmanagement.endpoints.web.exposure.includeincludescaches)
- GET
Example curl (actuator health / prometheus):
curl http://localhost:8080/actuator/health
curl http://localhost:8080/actuator/prometheusPrometheus & Grafana (compose)
- Prometheus UI: http://localhost:9090
- Prometheus scrapes the backend Prometheus endpoint (
/actuator/prometheus). The Prometheus configuration is included inbackend/prometheus/prometheus.yml(orprometheus/in the repo depending on docker-compose bind mounts).
- Prometheus scrapes the backend Prometheus endpoint (
- Grafana: http://localhost:3000
- Grafana is included in the compose stack and can be preconfigured to use Prometheus as a data source. You can add dashboards that visualize
http.server.requests,jvm, cache metrics and custom application metrics.
- Grafana is included in the compose stack and can be preconfigured to use Prometheus as a data source. You can add dashboards that visualize
Metrics you can expect
- HTTP server metrics (requests, response times):
http.server.requests - JVM metrics:
jvm.memory.*,jvm.gc.*,process.cpu.* - Data source metrics (HikariCP):
hikaricp.* - Cache metrics (if Micrometer integration present): cache hit/miss metrics per cache name
Security note
- Actuator endpoints may expose sensitive data. In production, lock down actuator endpoints with proper authentication and only expose the minimum required endpoints (for Prometheus, you usually only expose
/actuator/prometheusto the Prometheus server).
The backend uses Spring Cache with a Caffeine cache implementation for in-memory caching of frequently accessed read data (e.g., spot lists, building lookups). Key points:
- Cache provider: Caffeine (local in-memory cache)
- Abstraction: Spring Cache (
@Cacheable,@CacheEvict) β controllers/services annotate methods to cache results - Cache monitoring: If
management.endpoints.web.exposure.includeincludescaches, Actuator exposes/actuator/cachesto inspect cache names and some stats.
Typical cache usage examples (backend):
- Cache available spots per building/floor to reduce DB queries for rapidly-read data
- Cache building/floor metadata
- Short TTLs and explicit evicting on writes/events (e.g., when a reservation or check-in modifies spot status) to prevent stale reads
Cache safety notes
- Caffeine is an in-memory cache local to the JVM. In multi-instance (clustered) deployments consider using a distributed cache (Redis) or an event-driven cache invalidation strategy.
Base URL (local):
http://localhost:8080/api
Auth (public):
- POST /auth/register β RegisterRequest { fullName, email, password } -> AuthResponse
- POST /auth/login β LoginRequest { email, password } -> AuthResponse
User (JWT required):
- GET /user/dashboard β DashboardResponse
- GET /user/spots/available β List
- POST /user/reservation β ReservationRequest -> ReservationDTO
- POST /user/checkin β CheckInRequest -> SessionDTO
- POST /user/checkout/{sessionId}β -> BillDTO
Admin (Admin JWT required):
- GET /admin/dashboard
- GET /admin/users
- GET /admin/logs
For endpoint request/response shapes refer to docs/API_Documentation.md (placeholder) and backend controller DTO classes.
- Axios is configured centrally (look for
frontend/src/services/api.ts). The app uses an interceptor to addAuthorization: Bearer <token>from localStorage to outgoing requests. - Server-state is handled via
@tanstack/react-querylocated acrosssrc/pages/*andsrc/services/*. - Global auth state is in
frontend/src/store/authStore.ts(Zustand). - Routing & layout components live under
frontend/src/components/layoutand pages underfrontend/src/pages.
If you run into an import error like:
Uncaught SyntaxError: The requested module '/src/types/index.ts' does not provide an export named 'ApiError'
that typically means a type or exported symbol is referenced but not present in frontend/src/types/index.ts. Fix by either exporting the missing type from the types file or removing the import from the file that expects it.
- User registration & login (JWT)
- Role-based routing (User vs Admin)
- User dashboard with stats
- Browse available parking spots and check-in
- Create reservations
- Active session list and checkout (billing)
- Admin dashboard: user list, activity logs, parking lot management
- Observability endpoints via Actuator, Prometheus & Grafana
Backend:
cd backend
./gradlew testFrontend:
- No unit tests are included by default in the scaffold. Use
npm run lintfor static checks.
- A production build for the frontend can be produced with
cd frontend && npm run buildand then served by a static server or integrated into the backend build pipeline. - Backend is containerized via
backend/Dockerfileand can be deployed with Docker / Kubernetes.
Contributions are welcome. Suggested workflow:
- Fork the repo
- Create a feature branch
- Add tests where appropriate
- Open a PR describing the change
Please follow existing code style and run linting before opening pull requests.
This project is licensed under the MIT License. See the LICENSE file for details.
- Name: Antonio Santiago (TonyS-dev)
- GitHub: https://github.com/TonyS-dev
- Email: santiagor.acarlos@gmail.com
