Find a station · Start with a QR · Measure your impact · Earn rewards
| 🌍 Free no cost for the user |
📊 Measurable CO₂ avoided in real time |
🎮 Gamified XP, badges, leaderboards |
📱 Web + Mobile one app, everywhere |
- What GreenCharge is
- Features at a glance
- How it's built
- Signing in
- User guide
- Administrator guide
- Quick start
- Documentation
GreenCharge is the app for a smart charging station for electric bikes and scooters in a school environment. The service is free: the goal isn't to make money, but to encourage sustainable mobility by measuring and rewarding environmental savings (CO₂ avoided, energy from solar panels, equivalent trees).
With GreenCharge a user finds the nearest available station, starts charging with a QR code, follows the data in real time, earns points and badges, and compares results with friends. The administrator monitors the stations, manages the hardware and tickets, and exports the data.
| User | Administrator | |||
|---|---|---|---|---|
| ⚡ | Charge via signed QR or RFID card | 🖥️ | Live monitoring of every station | |
| 📈 | Real-time data: power, kWh, ETA, CO₂ | 🔧 | Hardware status control and IoT simulator | |
| 🗺️ | Stations map + congestion forecast | 🎫 | Tickets board organized in columns | |
| 🔔 | Virtual queue with push notification | 📤 | CSV export of sessions, consumption, users | |
| 🏆 | XP, badges, streaks, leaderboards, challenges | 🗄️ | Full CRUD over the database | |
| 👥 | Friends, activity feed and reactions | 📊 | Daily report and history | |
| 🌳 | Environmental impact and school data | 🏷️ | Signed QR generation per station |
Just an overview: the technical deep dive lives in ARCHITETTURA.md.
Four components revolve around a single MySQL database: a React web app (also shipped as a mobile app via Capacitor), an admin panel, a PHP REST backend with dual authentication (users via JWT, devices via Device Key), and the ESP32 IoT station (with a Python simulator for testing).
Core principle: the hardware never touches the database — it always goes through the API, the only component holding the DB credentials.
flowchart TB
DB[("🗄️ MySQL 8.0<br/>stazione_ricarica")]
API["🔌 PHP 8.2 REST backend<br/>JWT · Device Key"]
WEB["📱 React 18 frontend<br/>Web + Mobile (Capacitor)"]
IOT["⚡ IoT station<br/>ESP32 / Python simulator"]
WEB -- "Bearer JWT" --> API
IOT -- "X-Device-Key" --> API
API -- "PDO (backend only)" --> DB
| Component | Technology | Role |
|---|---|---|
| Database | MySQL 8.0 | Persistence; core logic in stored procedures and triggers |
| Backend | PHP 8.2 · Apache · PDO | REST API, authentication, application domain |
| Frontend | React 18 · Vite | User SPA + admin panel |
| Mobile | Capacitor | Native Android/iOS wrapper of the same SPA |
| IoT | ESP32 (Arduino) | Real station hardware |
| Orchestration | Docker Compose · Nginx | Build and runtime of the whole stack |
On launch the app opens the login screen. Depending on the role:
- 👤 User → taken to the Dashboard.
- 🛠️ Administrator → taken to the Admin Panel (the two areas are separate: an admin never sees the user pages and vice versa).
Important
One device per account. If you sign in on a new device with an account already logged in elsewhere, the previous device is signed out with the message "Logged in from another device".
Navigation happens through the side bar (desktop) or the bottom bar (mobile). On mobile you can also pull down from the top (pull-to-refresh) to reload the data.
- From the login page pick Sign up and enter first name, last name, email and password (phone number optional). During sign-up you can already add a vehicle.
- Confirm your email: you receive a verification link; until you confirm, login is rejected (you can request a new email from the login screen).
- Register at least one vehicle (bike or scooter): it's required to start a charge. Vehicles are managed in Settings → Your vehicles.
Tip
Deactivated your account? On your next login the app shows the reactivation screen (within 30 days of deactivation).
It's the user's home and brings together:
- Active charges — a card for each charge in progress with voltage, current, energy delivered, live CO₂ avoided, power, elapsed time, battery fill estimate, remaining time and ETA. From here you start a new charge or end one.
- "Unplug your vehicle" alerts — when a charge is finished but the vehicle is still plugged in, the station stays occupied: the dashboard reminds you.
- Quick stats — monthly kWh, CO₂ avoided, level and XP.
- Environmental impact — CO₂ avoided, equivalent km, equivalent trees.
- Station status and station battery (PowerWall).
- Active challenge with a progress bar.
The full cycle, in five steps:
① ② ③ ④ ⑤
🔗 ───────▶ 📷 ───────▶ ⚡ ───────▶ ⏹ ───────▶ 🔌
Plug in Scan the Charge End the Unplug
the vehicle QR code (live data) charge (XP+CO₂) the vehicle
- Tap ⚡ Start charge (in the Dashboard or on the Map). The scanner opens.
- Enter the current battery level (%) and, if you have more than one free vehicle, select which one you plugged in.
- Frame the station's QR code. The app checks that the QR is valid and signed; if it's forged or incomplete it rejects it.
- The charge starts: follow the live data in the Dashboard.
- End it with ⏹ Stop charge (or it completes on its own at 100%). Earned XP and CO₂ avoided are calculated.
- Unplug the vehicle: as long as it stays plugged in the station remains occupied and no one else can use it.
Note
- You can have multiple charges in parallel (one per vehicle).
- A plugged-in vehicle can't start a second charge until it's unplugged.
- A charge can also be started at the station with an RFID card.
The Map shows every station with markers colored by status:
| Marker | Status | Meaning |
|---|---|---|
| ⚡ | Free | available, you can start a charge right away |
| ✖ | Occupied | in use by another vehicle |
| ⏸ | Offline | unavailable (fault or maintenance) |
Tapping a marker shows the station's points, the power, the battery status and the congestion forecast (least busy day/time slot, computed automatically).
If a station is occupied, tap 🔔 Notify me when free to join the virtual queue: you get a push notification as soon as it frees up and you have priority. You can leave the queue at any time.
In Charge history you find every completed session:
- Filter by vehicle and summary KPIs (sessions, kWh, CO₂).
- A paginated table with date, duration, station/point, vehicle, kWh, CO₂, method.
- Charts: kWh by vehicle type and monthly trend.
- Export CSV (on mobile via the system share sheet).
- At the bottom, the monthly recap of consumption.
The Rewards page gathers:
- Weekly streak with an XP multiplier (charge every week so you don't lose it; at 4 weeks the multiplier activates the following month).
- Top 10 leaderboard (your row is highlighted).
- Sustainability tree that grows with your level.
- Badges earned and to unlock (with the condition for each).
- Active challenges with progress, XP reward and days remaining.
Built into the Rewards page:
- Invite a friend with a personal link: whoever opens it becomes your friend.
- Requests received/sent, friends list, and suggestions of people who use your same stations.
- Activity feed (friends' charges) and goals feed (badges, challenges, level-ups) where you can leave emoji reactions.
The School Data page shows the Green School project, monthly energy consumption, the year-over-year comparison, the building data (surface, energy class, solar panels), the station's impact and the active green initiatives.
- Personal data: first name, last name, town, profile photo (upload and removal).
- Your vehicles: add/remove bikes and scooters.
- Push notifications: choose which to receive (charge completed, station free, friend requests, leaderboard overtake, streak at risk, recap, reactions).
- Appearance: primary color and light/dark theme.
- Account deletion: deactivation with a 30-day window to change your mind, then permanent deletion.
From Settings you can open a ticket (station fault, maintenance, app bug, other) with a title, description, the station involved, and optional photo and GPS location. Follow the status (open → in progress → resolved/closed) and read the admin's reply.
The admin accesses a dedicated area, separate from the user pages.
- Daily report: today's sessions, kWh and active users, plus the history by vehicle type.
- Data export (CSV): download the Sessions, Consumption, Tickets and Users datasets (with a date-range filter where applicable).
- Registered users: list with role, level, XP, sessions and total kWh.
A single page that brings together all station control:
- Daily live KPIs (active/today sessions, kWh delivered, CO₂ avoided).
- For each station: live output (power/kWh in real time, refreshed every 5 seconds) and connection status.
- Hardware status: set Online / Offline / Fault / Maintenance (not editable while a station is occupied).
- Built-in IoT simulator: Plug in vehicle (activates the QR), Send tick (telemetry), End, Unplug — to test the flow without real hardware.
- Generate the station's signed QR (to print/show).
A column board (Open → In progress → Resolved). Opening a ticket shows the description, photo and GPS; you can change status, write a reply to the user and assign it to yourself.
Full CRUD over every database table: browse the tables, search across rows (pagination), add, edit, duplicate and delete records. The form adapts automatically to the column types (enum, boolean, date, etc.).
Warning
These are direct operations on the database, with no safety net: use with extreme care.
The whole stack (database, backend, frontend, backup, phpMyAdmin) runs locally inside Docker: no remote server needed.
Prerequisites
- Docker 24+ and Docker Compose v2
- At least 4 GB of available RAM
- Free ports on the host:
80(frontend),8080(API),8085(phpMyAdmin)
cp .env.example .env
# Generate strong secrets (macOS/Linux):
# openssl rand -hex 48 → JWT_SECRET
# openssl rand -hex 32 → DEVICE_KEY
# openssl rand -base64 24 → DB_PASSWORD and DB_ROOT_PASSWORD
# Open .env and replace the "__cambiami__" placeholders.
docker compose up -d --buildOnce the stack is up:
| Service | URL | Notes |
|---|---|---|
| 🌐 Web app | http://localhost |
port FRONTEND_PORT (default 80) |
| 🔌 API | http://localhost:8080/api |
port BACKEND_PORT (default 8080) |
| 🗄️ phpMyAdmin | http://localhost:8085 |
host db, user greencharge |
Demo account (local testing only) in the seed file
database/04_seed_extension.sql.
Caution
Change passwords and secrets before any public deployment.
Tip
Mobile build (optional). The frontend/ios and frontend/android folders
contain pre-built Capacitor bundles pointing at the original server URL. To use
your local Docker install: set VITE_API_BASE_URL in
frontend/.env.mobile (see the comments inside the
file), then run npm run build:mobile && npx cap sync from the frontend/
folder.
Full deployment guide: docs/DEPLOY.md.
| Document | Content |
|---|---|
| 🏗 ARCHITETTURA.md | In-depth technical documentation (backend, database, frontend, IoT, security) |
🔌 docs/API.md |
REST API reference |
🗄️ docs/SCHEMA.md |
Database structure |
🐳 docs/DEPLOY.md |
Docker deployment (recommended) |
🖥️ docs/DEPLOY-PROXMOX.md |
Optional guide: hosting the stack on a Linux VM in Proxmox |
⚙️ iot-firmware/README.md |
ESP32 firmware and wiring |
GreenCharge — sustainable charging, free and measurable. 🌿