/* voltgrid */ → code
VoltGrid Code
Sustainable code is layered: HTTP stays thin, business logic lives in reusable services, and every layer is testable on its own. Here a request travels through the backend layers, and on the frontend, a util, a composable and a UI primitive compose into a button without anything existing twice.
// backend, a request travels through the layers
The controller only translates HTTP: request in, resource out. No logic, nothing to mock.
final class SessionController
{
public function store(StartSessionRequest $request, StartChargingSession $action): JsonResponse
{
return SessionResource::make($action->handle($request->toCommand()))
->response()
->setStatusCode(201);
}
}The action is the use case: guards with dedicated exception classes, then delegation to the domain. Testable in isolation, exactly what the test suite page exercises.
final class StartChargingSession
{
public function __construct(
private readonly StationRepository $stations,
private readonly TariffCalculator $tariff,
private readonly EventDispatcher $events,
) {
}
public function handle(StartSessionCommand $command): ChargingSession
{
$station = $this->stations->findOrFail($command->stationId);
if (! $station->supports($command->connectorType)) {
throw new UnsupportedConnectorException($station, $command->connectorType);
}
if (! $station->isAvailable()) {
throw new StationUnavailableException($station);
}
$estimate = $this->tariff->estimate($station, $command->estimatedKwh);
$session = ChargingSession::start($station, $command->connectorType, $estimate);
$this->events->dispatch(new SessionStarted($session));
return $session;
}
}The service is the single source of truth for pricing: value objects in (KilowattHours), Money out. No framework imports, pure, reusable domain logic.
final class TariffCalculator
{
public function __construct(private readonly TariffRepository $tariffs)
{
}
public function estimate(Station $station, KilowattHours $kwh): Money
{
$tariff = $this->tariffs->activeFor($station);
return $tariff->pricePerKwh()
->multiply($kwh->value())
->add($tariff->baseFee());
}
}↺ reused by: StartChargingSession · FinalizeSessionInvoice · GET /stations/{id}/price-preview
The proof of reuse: the billing worker in the queue uses the exact same service, live estimate and invoice can never drift apart.
final class FinalizeSessionInvoice implements ShouldQueue
{
public function __construct(private readonly TariffCalculator $tariff)
{
}
public function handle(SessionCompleted $event): void
{
// derselbe TariffCalculator wie im Live-Estimate:
// ein Preis-Codepfad · Anzeige und Rechnung können nie abweichen
$amount = $this->tariff->estimate($event->station, $event->chargedKwh);
Invoice::issueFor($event->session, $amount);
}
}// frontend, util → composable → component
One util for every form: the API's 422 responses are translated into field errors in exactly one place.
// utils/http.ts
export function extractFieldErrors(error: unknown): Record<string, string> {
if (isFetchError(error) && error.statusCode === 422) {
return error.data?.data?.errors ?? {}
}
return { _global: 'unexpected error, please retry' }
}↺ reused by: useChargingSession · useStationFilter · useOperatorLogin
The composable encapsulates state as a discriminated union, impossible states cannot be represented, and any component can use it.
// composables/useChargingSession.ts
type SessionState =
| { status: 'idle' }
| { status: 'starting' }
| { status: 'charging', session: SessionReceipt }
| { status: 'failed', errors: Record<string, string> }
export function useChargingSession() {
const state = ref<SessionState>({ status: 'idle' })
async function start(payload: StartSessionPayload): Promise<void> {
state.value = { status: 'starting' }
try {
const { data } = await $fetch<{ data: SessionReceipt }>('/api/v1/sessions', {
method: 'POST',
body: payload,
})
state.value = { status: 'charging', session: data }
}
catch (error) {
state.value = { status: 'failed', errors: extractFieldErrors(error) }
}
}
const isCharging = computed(() => state.value.status === 'charging')
return { state: readonly(state), start, isCharging }
}The component only composes: logic from the composable, looks from the DgButton primitive. Seven lines, nothing duplicated.
<script setup lang="ts">
const props = defineProps<{ stationId: number }>()
const { state, start, isCharging } = useChargingSession()
</script>
<template>
<DgButton
:disabled="isCharging"
@click="start({ stationId: props.stationId, connectorType: 'CCS', estimatedKwh: 40 })"
>
{{ isCharging ? '⚡ lädt …' : '→ laden' }}
</DgButton>
</template>↺ DgButton is the same primitive used across this whole site, one style, one place to change it
// Conventions from real projects: method parameters always type-hinted, errors as dedicated exception classes instead of generic try/catch, comments only where business logic needs explaining.