![CitrineOS Logo](logo_white.png#gh-dark-mode-only)
![CitrineOS Logo](logo_black.png#gh-light-mode-only)

<div align="center">
<img src="OCPP_201_Logo_core_and_advanced_security.png" alt="CitrineOS Certification Logo" width="200" height="100" />
</div>

# Welcome to CitrineOS

CitrineOS is an open-source project aimed at providing a modular server runtime for managing Electric Vehicle (EV)
charging infrastructure. This repository (`citrineos-core`) is a **pnpm monorepo** containing the charging station
management logic, OCPP message routing, the related services, and the operator-facing web UI.

This README covers the repository as a whole: how it is structured, how to install and build it, and how to run the
full stack. Each application and package also has its own README with deeper, component-specific documentation —
see [Repository Structure](#repository-structure) and [Component Documentation](#component-documentation).

All other documentation and the issue tracking can be found in our main repository
here: <https://github.com/citrineos/citrineos>.

## Table of Contents

- [Overview](#overview)
- [Architecture Flow](#architecture-flow)
- [Repository Structure](#repository-structure)
- [Prerequisites](#prerequisites)
- [Installation](#installation)
- [Running the Full Stack with Docker](#running-the-full-stack-with-docker)
- [Information on Docker Setup](#information-on-docker-setup)
- [Workspace Scripts](#workspace-scripts)
- [Component Documentation](#component-documentation)
- [Contributing](#contributing)
- [Licensing](#licensing)
- [Support and Contact](#support-and-contact)
- [Roadmap](#roadmap)

## Overview

CitrineOS is developed in TypeScript and runs on `NodeJS` with [ws](https://github.com/websockets/ws)
and [fastify](https://fastify.dev/). The operator UI is built with [Next.js](https://nextjs.org/) and
[Refine](https://refine.dev/).

The system features:

- Dynamic **OCPP 1.6 and 2.0.1** message schema validation, prior to transmission using `AJV`
- Generated OpenAPIv3 specification for easy developer access
- Configurable logical modules with decorators
  - `@AsHandler` to handle incoming OCPP messages (1.6 or 2.0.1)
  - `@AsMessageEndpoint` to expose functions allowing sending messages to charging stations
  - `@AsDataEndpoint` to expose CRUD access to data entities
- Utilities to connect and extend various message broker and cache mechanisms
  - Currently supported broker is **RabbitMQ**
  - Currently supported caches are **In Memory** and **Redis**
- A web-based **Operator UI** for managing locations, stations, transactions, and authorizations

For more information on the project go to [citrineos.github.io](https://citrineos.github.io).

## Architecture Flow

Here's a **flowchart-style overview** of CitrineOS architecture and message flow:

```text
┌───────────────────┐                         ┌───────────────────┐
│ Charging Stations │                         │   Operator UI     │
│  (OCPP 1.6 &      │                         │ (Next.js + Refine)│
│   2.0.1)          │                         └───┬───────────┬───┘
└────────┬──────────┘                  REST (Data │           │ GraphQL
         │ WebSocket                & Message API)│           │
         ▼                                        ▼           ▼
┌───────────────────┐                 ┌───────────────────┐ ┌──────────────┐
│  CitrineOS Server │                 │  CitrineOS Server │ │   Hasura     │
│  (OCPP Router +   │                 │   (HTTP / REST)   │ │GraphQL Engine│
│   Modules)        │                 └───────────────────┘ └──────┬───────┘
└────────┬──────────┘                                              │
         │                                                         │
   ┌─────┴─────────┐                    ┌─────────────┐            │
   ▼               ▼                    │ File Storage│            ▼
┌─────────────┐ ┌─────────────┐         │ (S3 / GCS / │      ┌─────────────┐
│ Message     │ │ PostgreSQL  │         │  MinIO)     │      │ PostgreSQL  │
│ Broker      │ │ (PostGIS)   │         └─────────────┘      │ (PostGIS)   │
│ (RabbitMQ)  │ │ Persistence │                              │ (same DB)   │
└─────────────┘ └─────────────┘                              └─────────────┘
```

### Flow Overview

1. **Charging Stations** send messages using **OCPP 1.6** or **OCPP 2.0.1**.
2. **CitrineOS Server** receives and routes messages via **WebSocket** to the **OCPP Router**.
3. The **Message Broker (RabbitMQ)** handles **inter-module communication**, enabling asynchronous processing between the OCPP Router and other server modules.
4. Operational and configuration data are persisted in **PostgreSQL** (with the PostGIS extension).
5. Files and assets are stored in **Amazon S3** or **Google Cloud Storage (GCS)** in supported environments. **MinIO** is used for **local development**, providing **S3-compatible storage**. Local development does **not** support a GCS-compatible storage backend.
6. The **Operator UI** reads data through the **Hasura GraphQL Engine** (which queries the same PostgreSQL database) and sends commands and manages entities through the server's **REST Data and Message APIs**.

## Repository Structure

This repository is a **pnpm monorepo** with the following workspace members:

```
citrineos-core/
├── apps/
│   ├── Server/          # OCPP server entrypoint, Docker setup, migrations (@citrineos/server)
│   └── operator-ui/     # Operator web UI — Next.js + Refine (@citrineos/operator-ui)
├── packages/
│   ├── base/            # Shared types, interfaces, and utilities (@citrineos/base)
│   └── core/            # Core OCPP modules and logic (@citrineos/core)
├── docker-compose.yml        # Full stack from published ghcr.io images (server + UI)
├── docker-compose.local.yml  # Full stack, server built from local source
├── package.json              # Root workspace scripts
└── pnpm-workspace.yaml        # pnpm workspace configuration
```

Each workspace member documents itself:

- **Server** — running the server, configuration, bootstrap env vars, migrations, OCPP interfaces, EVerest testing: [`apps/Server/README.md`](./apps/Server/README.md)
- **Operator UI** — running and developing the web UI, bringing a station online end-to-end: [`apps/operator-ui/README.MD`](./apps/operator-ui/README.MD)

## Prerequisites

Before you begin, make sure you have the following installed on your system:

- Node.js (v24.16.0 or higher): [Download Node.js](https://nodejs.org/)
- pnpm (the workspace's package manager): [Download pnpm](https://pnpm.io/installation)
- Docker (Optional). Version >= 20.10: [Download Docker](https://docs.docker.com/get-docker/)

## Installation

1. Clone the CitrineOS repository to your local machine:

   ```shell
   git clone https://github.com/citrineos/citrineos-core
   ```

1. Install all workspace dependencies from the root directory:

   ```shell
   pnpm install
   ```

1. Build all packages from the root directory:

   ```shell
   pnpm run build
   ```

## Running the Full Stack with Docker

The quickest way to get a complete environment running is via the root-level Docker Compose files, which start the
server, the operator UI, RabbitMQ, PostgreSQL, MinIO, and Hasura together.

- **From published images** (no build required) — run from the repository root:

  ```shell
  docker compose up -d
  ```

- **With the server built from local source** — run from the repository root:

  ```shell
  docker compose -f docker-compose.local.yml up -d
  ```

Once everything is up, the operator UI is available at [http://localhost:3000](http://localhost:3000) and the server's
Swagger docs at [http://localhost:8080/docs](http://localhost:8080/docs).

To run just the backend (no operator UI), or to run the server directly with pnpm for development, see the
[Server README](./apps/Server/README.md). To develop the UI on its own, see the
[Operator UI README](./apps/operator-ui/README.MD).

## Information on Docker Setup

You need to install
[docker](https://docs.docker.com/engine/install/#server) (>= 20.10) and
[docker-compose](https://docs.docker.com/compose/install/#install-compose).
Furthermore, [Visual Studio Code](https://code.visualstudio.com/docs/setup/linux) might be handy as a common
integrated development environment.

There are three Compose files:

- `docker-compose.yml` (repository root) — full stack from published `ghcr.io` images, including the operator UI.
- `docker-compose.local.yml` (repository root) — full stack with the server built from local source.
- `apps/Server/docker-compose.yml` — backend only (no operator UI), server built from local source (see the [Server README](./apps/Server/README.md)).

Once a stack is running, the following services should be available:

- **CitrineOS Server** (service name: citrine)
  - `8080`: webserver HTTP - [Swagger](http://localhost:8080/docs)
  - `8081`: websocket server TCP connection without auth
  - `8082`: websocket server TCP connection with basic HTTP auth
  - `8083`: additional websocket server
  - `8443` / `8444`: TLS websocket servers
  - `9229`: Node.js debugger
- **Operator UI** (service name: citrine-ui) — only in the root-level Compose files
  - `3000`: [Operator UI](http://localhost:3000)
- **RabbitMQ Broker** (service name: amqp-broker)
  - `5672`: AMQP TCP connection
  - `15672`: RabbitMQ [management interface](http://localhost:15672)
- **PostgreSQL** (service name: ocpp-db), PostGIS-enabled PostgreSQL database for persistence
  - `5432`: SQL TCP connection
- **MinIO** (service name: minio) for S3-compatible local file storage
  - `9000`: S3 API endpoint
  - `9001`: MinIO [web console](http://localhost:9001)
- **Hasura GraphQL Engine** (service name: graphql-engine)
  - `8090`: [Hasura console](http://localhost:8090)

These services live inside the docker network with their respective ports. By default these ports are directly
accessible using `localhost:8080` for example.

## Workspace Scripts

These scripts are run from the repository root and operate across the whole workspace.

### Building

- `pnpm run build` - builds all packages
- `pnpm run start` - starts the CitrineOS server (delegates to `@citrineos/server`)

### Running `clean` and `fresh`

The workspace consists of multiple `pnpm` packages that are loaded as dependencies when running the application. This
means packages need to be rebuilt when their files change. In some cases — in particular when switching between
branches, especially when there are changes in a `package.json` — the already built `dist` as well as the generated
`pnpm-lock.yaml` may become invalid.

To alleviate the above, we created the following commands (run from the root directory):

- `pnpm run fresh` - deletes all `node_modules`, `dist`, `tsbuildinfo`, and `pnpm-lock.yaml`, then clears the pnpm cache
- `pnpm run clean` - subset of `pnpm run fresh`; only deletes build artifacts (`dist` and `tsbuildinfo`)
- `pnpm run fi` - convenience command that runs `fresh` followed by `pnpm install`

### Linting and Prettier

ESLint and Prettier have been configured to help support syntactical consistency throughout the codebase.

- `pnpm run prettier` - runs Prettier and formats the files
- `pnpm run lint` - runs the linter
- `pnpm run lint-fix` - runs Prettier and the linter with the `--fix` flag, which attempts to resolve any linting issues

### Testing

- `pnpm run test` - runs the test suite with Vitest
- `pnpm run coverage` - runs the test suite with coverage

## Component Documentation

- [CitrineOS Server (`@citrineos/server`)](./apps/Server/README.md) — running the server, configuration, bootstrap
  environment variables, database migrations, OCPP interface generation, custom DataTransfer validation,
  auto-commissioning, Hasura metadata, and EVerest testing.
- [CitrineOS Operator UI (`@citrineos/operator-ui`)](./apps/operator-ui/README.MD) — running and developing the web UI,
  and a step-by-step guide to bringing a charging station online end-to-end.
- [Testing with EVerest](./apps/Server/everest/README.md) — running the EVerest charger simulator against CitrineOS.

## Contributing

We welcome contributions from the community. If you would like to contribute to CitrineOS, please follow
our [contribution guidelines](https://github.com/citrineos/citrineos/blob/main/CONTRIBUTING.md).

## Licensing

CitrineOS and its subprojects are licensed under the Apache License, Version 2.0. See LICENSE for the full license text.

## Support and Contact

If you have any questions or need assistance, feel free to reach out to us on our community forum or create an issue on
the GitHub repository.

## Roadmap

[Roadmap](https://citrineos.github.io/docs/roadmap.html)
