---
title: "Real-life scenario: ChargeGrid"
chapter: "18"
---

# Real-life scenario: ChargeGrid

ChargeGrid operates 70,000 EV chargers from multiple vendors. Sites remain
available during network loss, tariffs change by region, and operators deploy
connector fixes without rebuilding the whole control station.

## Requirements

- each vendor protocol is replaceable;
- core billing never imports vendor implementation packages;
- connector configuration can create one instance per site;
- offline commands queue with bounded storage;
- duplicated messages never create duplicate charges;
- operators can diagnose one site without exposing credentials;
- updates are signed, staged, observable, and reversible.

## Bundle map

```text
chargegrid.model.api       records, IDs, money, states
chargegrid.connector.api   ChargerConnector service contract
chargegrid.session.core    charging-session state machine
chargegrid.tariff.api      TariffService contract
chargegrid.vendor.ocpp     OCPP connector implementation
chargegrid.vendor.legacy   legacy serial connector
chargegrid.persistence     checkpoint and idempotency store
chargegrid.http            HTTP/Jakarta REST whiteboard resources
chargegrid.operations      health, commands, support snapshot
```

API bundles export small packages. Implementation bundles export nothing.
`session.core` imports only model and service API packages.

## Dynamic services

Each vendor bundle publishes `ChargerConnector` with properties:

```text
protocol=ocpp
protocol.version=2.0.1
region=eu
secure=true
```

The station coordinator has a multiple DS reference and indexes connectors by
declared protocol. Removing one connector stops new assignments, drains bounded
work, checkpoints state, and then unbinds.

## Configuration

A factory PID creates one `SiteConnector` component per charging site. Typed
Metatype declares endpoint, site ID, TLS profile, timeout, and concurrency.
Secrets are references to a vault-backed `CredentialService`, not literal
passwords in ConfigAdmin.

## Correctness

Every command has a durable `(siteId, commandId)` idempotency key. Session state
changes and outbound intent commit together. A dispatcher retries safe commands
with deadlines and jitter. Reconciliation compares station counters, accepted
events, and billed energy.

## Karaf assembly

Karaf 4.4.11 provides the managed runtime. A versioned ChargeGrid features
repository installs SCR, ConfigAdmin, HTTP, logging, APIs, then implementations.
Provisioning occurs from a signed internal repository with no public shell.

## Failure walkthrough

When the OCPP service disappears:

1. DS unbinds the connector from the coordinator.
2. New OCPP work is rejected or queued within a fixed site quota.
3. Existing calls reach a deadline; no lock spans the network.
4. Idempotency makes a later retry safe.
5. Health shows the affected protocol and site count.
6. The legacy connector and core tariff services remain active.

## Upgrade

A connector API addition passes bnd baseline as a minor-compatible change.
The new provider is installed beside the old one with a higher service ranking
only for a canary site filter. Metrics and reconciliation prove correctness
before the remaining configurations move. Rollback restores ranking and config;
the data format remains backward compatible.

## Architecture verdict

OSGi fits because connector diversity, long-lived edge runtimes, controlled
plugin boundaries, and partial updates are primary requirements. If ChargeGrid
were one stateless cloud API redeployed as a unit, a plain modular Java service
might be simpler.

## Feynman check

Trace one “start charging” command through HTTP service, session core, connector
selection, durable idempotency, vendor service, event result, and telemetry.
Then explain what happens at every step if the connector vanishes.
