- CitrineOS core extracted (CSMS OCPP 2.0.1) - OpenOCPP extracted (firmware OCPP 1.6J/2.0.1) - ShapeShifter library installed (pip install -e) - ShapeShifter specification extracted - EVerest extracted TODO updated with progress
Welcome to CitrineOS Operator UI
CitrineOS Operator UI is the web-based operator interface for CitrineOS, an open-source, modular backend platform for managing Electric Vehicle (EV) charging infrastructure.
This repository contains the Operator-facing User Interface and related tooling.
It is designed to work together with CitrineOS Core, which provides the charging station management logic,
OCPP message handling, persistence layer, and GraphQL APIs.
⚠️ Important:
The Operator UI does not run standalone.
A running instance of CitrineOS Core (including Hasura GraphQL Engine) is required.
This app is one workspace member of the citrineos-core pnpm monorepo. For repository-wide setup and for running the
full stack (server + UI + Hasura) together, see the root README.
Table of Contents
- Overview
- Architecture & Data Flow
- Prerequisites
- Getting Started
- Working with
@citrineos/base - Build & Development Workflow
- Running the Application
- Bringing a Charging Station Online (End-to-End)
- Usage
- Hasura Authentication
- Related Documentation
- Contributing
- Licensing
- Support & Contact
Overview
The CitrineOS Operator UI provides operators with:
- Visibility into charging stations, connectors, sessions, and transactions
- Operational controls via CitrineOS Core Message APIs
- Data access through Hasura GraphQL Engine
- A modern React-based UI built with Refine
The UI consumes:
- Hasura GraphQL APIs for data access
- CitrineOS Core Message APIs for sending commands to charging stations
- CitrineOS Core Data APIs for managing entities
Architecture & Data Flow
+-------------------+ GraphQL +----------------------+
| | <----------------> | |
| Operator UI | | Hasura GraphQL |
| | | Engine |
| | | |
+-------------------+ +----------+-----------+
|
| SQL
|
+---------v-----------+
| |
| PostgreSQL |
| |
+---------------------+
+-------------------+ REST +--------------------------+
| Operator UI | <--------------> | CitrineOS Core |
| | | (OCPP 1.6 & 2.0.1) |
+-------------------+ +--------------------------+
Prerequisites
Before starting, ensure the following tools and services are installed and running.
-
Node.js (v24.16.0 or higher)
Link -
pnpm
Link — the workspace's package manager -
Docker & Docker Compose (recommended)
Link
The following services must be available before starting the application:
-
CitrineOS Core
Backend service responsible for OCPP 1.6 and OCPP 2.0.1 handling, charging station management, and APIs. -
Hasura GraphQL Engine
GraphQL layer used for data access and management.
References:
-
CitrineOS Core Repository
Documentation -
Hasura Documentation
Documentation
Getting Started
Running with Docker (Recommended)
If CitrineOS Core is already running via Docker, the Operator UI can be started with a single command:
docker compose up -d
This will:
- Build the Operator UI container
- Start the UI connected to the configured Hasura and Core service
Running with pnpm (Local Development)
The Operator UI lives inside the citrineos-core pnpm workspace (under apps/operator-ui). Install all
workspace dependencies once from the repository root, then start the dev server:
# from the repository root
pnpm install
# then, from apps/operator-ui
pnpm run dev
This starts the development server (Next.js + Refine) with hot reload.
Working with @citrineos/base
The Operator UI depends on @citrineos/base via a workspace:* dependency, so pnpm resolves it from the local
packages/base automatically — no npm link step is required. Just build the workspace packages so the compiled
output is available:
# from the repository root
pnpm run build
Build & Development Workflow
The Operator UI is a member of the citrineos-core pnpm workspace.
Typical Workflow
- Install and build the workspace from the repository root:
# from the repository root
pnpm install
pnpm run build
- Start the dev server:
# from apps/operator-ui
pnpm run dev
Running the Application
Development Mode
pnpm run dev
- Runs the app with hot reload
- Default URL: http://localhost:3000
Production Build
pnpm run build
pnpm run start
- Production URL: http://localhost:3000
Bringing a Charging Station Online (End-to-End)
This section describes the minimum operational steps required to bring a charging station online using:
- CitrineOS Operator UI
- CitrineOS Core
- EVerest simulator
These steps are required even for local development and testing.
Create a Location
In CitrineOS, all charging stations must belong to a Location.
- Open CitrineOS Operator UI:
- Navigate to:
Locations → Create Location
- Fill in the required metadata (name, address, country, etc.)
- Save the Location
A Location represents a physical site such as a parking garage, depot, or charging hub.
Add a Charging Station (Charge Point)
To add a new charging station in CitrineOS Operator UI:
- Navigate to:
Charging Stations → Add Charging Station
-
Select the previously created Location.
-
Use the default Charge Point ID:
cp001
⚠️ Important: The Charge Point ID must exactly match the ID used by your physical charging station or simulator. By default, EVerest uses
cp001.
- Click Save to create the charging station.
Add an EVSE (Electric Vehicle Supply Equipment)
Each Charging Station must contain at least one EVSE.
- Open the Charging Station you just created.
- Navigate to:
EVSEs → Add EVSE
- Use a numeric EVSE ID (example:
1). - Click Save.
EVSEs represent physical charge points within a station (e.g., left/right ports).
Add a Connector
Each EVSE must have at least one Connector.
- Open the EVSE.
- Navigate to:
Connectors → Add Connector
- Choose:
- Connector ID (example:
1) - Connector type (Type2, CCS, etc.)
- Connector ID (example:
- Click Save.
Without a Connector, charging sessions cannot be started.
Add an Authorization (ID Token)
To allow charging sessions, an ID Token must be authorized.
- Navigate to:
Authorizations → Add Authorization
- Create an ID Token (RFID, app token, etc.)
- Mark it as Accepted
- Click Save
⚠️ Note: This token will be used by EVerest to start charging. The EVerest simulator uses the default RFID token
DEADBEEF(ISO14443).
Start the Charging Station (EVerest)
Now that the backend configuration is complete, start the EVerest simulator:
cd citrineos-core/apps/Server
pnpm run start-everest
This will: In Operator UI
- Navigate to Charging Stations
- Status should show:
Online
You can now track OCPP logs for the charging station.
Usage
Once running, the Operator UI allows you to:
- View and manage charging stations and connectors
- Monitor transactions and sessions
- Trigger charging station commands (via CitrineOS Core)
- Query and manage data through Hasura-backed GraphQL APIs
Hasura Authentication
There are two ways to authenticate to Hasura:
- If you have *uncommented the Docker environment variable
HASURA_GRAPHQL_ADMIN_SECRETincitrineos-core: 2. Ensure your.env.localhas theHASURA_ADMIN_SECRETuncommented out 3. Please note that it is not recommended to use a Hasura Admin Secret in production. - If you have commented the Docker environment variable
HASURA_GRAPHQL_ADMIN_SECRETincitrineos-core: 5. Ensure your.env.localhas theHASURA_ADMIN_SECRETcommented out, as the auth will be handled by your auth provider automatically.
Related Documentation
- CitrineOS Core
- CitrineOS Project Docs
- Refine
- Hasura GraphQL Engine
- Postgres Data Connector
Contributing
We welcome contributions from the community. If you would like to contribute to CitrineOS, please follow our contribution guidelines.
Licensing
CitrineOS and its subprojects are licensed under the Apache License, Version 2.0.
Support and Contact
If you need help or want to report an issue:
- Open an issue on GitHub
- Reach out via the CitrineOS community channels


