Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions CURRENT_STATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@

- Repository scaffolded: Next.js 16 (App Router), Tailwind v4, strict TypeScript,
ESLint, Playwright.
- Web app migrated from `toolkit/apps/web` — landing, root layout, inspector, and
all docs pages — with **no behavior change**.
- The `/inspector` route now consumes the **published** `@ocpp-debugkit/toolkit`
npm package (`^0.3.1`) instead of a workspace dependency, decoupling the site
from the toolkit's build.
- Web app migrated from `toolkit/apps/web` with **no behavior change**; the
`/inspector` route consumes the **published** `@ocpp-debugkit/toolkit` npm
package (`^0.3.1`), decoupling the site from the toolkit's build.
- **Umbrella content:** the landing and docs cover **both** products — `toolkit`
(library · CLI · web inspector) and `studio` (native desktop app). Added a
shared site header, a two-product landing (comparison table + interop note), a
Studio overview page, and a Studio download/install page. Marketing and the
scenarios doc refreshed to the current toolkit surface — 16 detection rules and
15 scenarios, source-verified.
- CI: typecheck, lint, build, and Playwright end-to-end tests.
- Community docs and issue/PR templates.

## What's Next

- **Umbrella rework:** make the landing and docs cover **both** products —
`toolkit` (library · CLI · web inspector) and `studio` (native desktop app) —
including a Studio overview, a download/install page, and a refresh of the
marketing content to the current toolkit version.
- **Go-live:** import the repo into Vercel; then retire the old
`toolkit/apps/web` so this becomes the canonical site.

Expand Down
72 changes: 45 additions & 27 deletions src/app/docs/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,57 @@
import Link from 'next/link';
import SiteHeader from '@/components/SiteHeader';

const docPages = [
{ href: '/docs/quickstart', label: 'Quick Start' },
{ href: '/docs/glossary', label: 'Glossary' },
{ href: '/docs/architecture', label: 'Architecture' },
{ href: '/docs/trace-format', label: 'Trace Format' },
{ href: '/docs/cli', label: 'CLI Reference' },
{ href: '/docs/scenarios', label: 'Scenarios' },
const docGroups = [
{
title: 'Toolkit',
pages: [
{ href: '/docs/quickstart', label: 'Quick Start' },
{ href: '/docs/glossary', label: 'Glossary' },
{ href: '/docs/architecture', label: 'Architecture' },
{ href: '/docs/trace-format', label: 'Trace Format' },
{ href: '/docs/cli', label: 'CLI Reference' },
{ href: '/docs/scenarios', label: 'Scenarios' },
{ href: '/docs/scenario-assertions', label: 'Scenario Assertions' },
{ href: '/docs/trace-diffing', label: 'Trace Diffing' },
{ href: '/docs/ci-mode', label: 'CI Mode' },
{ href: '/docs/anonymize', label: 'Anonymize' },
{ href: '/docs/examples', label: 'Examples' },
],
},
{
title: 'Studio',
pages: [
{ href: '/docs/studio', label: 'Overview' },
{ href: '/docs/studio/install', label: 'Download & Install' },
],
},
];

export default function DocsLayout({ children }: { children: React.ReactNode }) {
return (
<div className="min-h-screen bg-white dark:bg-neutral-950">
<header className="border-b border-neutral-200 dark:border-neutral-800">
<div className="mx-auto max-w-5xl px-6 py-4">
<Link href="/" className="text-lg font-bold text-neutral-900 dark:text-white">
OCPP DebugKit
</Link>
<span className="ml-2 text-sm text-neutral-500">Docs</span>
</div>
</header>
<SiteHeader />
<div className="mx-auto max-w-5xl px-6 py-8 flex gap-8">
<nav className="w-48 shrink-0">
<ul className="space-y-1">
{docPages.map((page) => (
<li key={page.href}>
<Link
href={page.href}
className="block rounded px-3 py-1.5 text-sm text-neutral-600 hover:bg-neutral-100 dark:text-neutral-400 dark:hover:bg-neutral-900"
>
{page.label}
</Link>
</li>
))}
</ul>
{docGroups.map((group) => (
<div key={group.title} className="mb-6">
<p className="px-3 pb-1 text-xs font-semibold uppercase tracking-wide text-neutral-400 dark:text-neutral-500">
{group.title}
</p>
<ul className="space-y-1">
{group.pages.map((page) => (
<li key={page.href}>
<Link
href={page.href}
className="block rounded px-3 py-1.5 text-sm text-neutral-600 hover:bg-neutral-100 dark:text-neutral-400 dark:hover:bg-neutral-900"
>
{page.label}
</Link>
</li>
))}
</ul>
</div>
))}
</nav>
<main className="flex-1 min-w-0 prose prose-neutral dark:prose-invert max-w-none">
{children}
Expand Down
155 changes: 102 additions & 53 deletions src/app/docs/scenarios/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,83 +3,132 @@ export default function ScenariosPage() {
<div>
<h1>Scenarios</h1>
<p>
Scenarios are predefined trace fixtures that test the analysis engine. Each scenario has a
trace and a list of expected failures.
Scenarios are predefined trace fixtures that test the analysis engine. Each scenario pairs a
trace with the failures it is expected to produce, so the detection engine can be checked
against known-good and known-bad sessions.
</p>

<h2>Built-in Scenarios</h2>
<p>DebugKit v0.1 includes 5 scenarios:</p>

<h3>normal-session</h3>
<p>
A complete charging session: boot, authorize, start transaction, meter values, stop
transaction. No failures expected.
</p>
<p>The toolkit ships 15 scenarios:</p>
<ul>
<li>
<code>expectedFailures: []</code>
<strong>normal-session</strong> — a complete session (boot, authorize, start, meter
values, stop) with no failures expected.
</li>
</ul>

<h3>failed-auth</h3>
<p>
Failed authorization: the idTag is rejected by the CSMS. StartTransaction is not attempted.
The connector transitions to Faulted.
</p>
<ul>
<li>
<code>expectedFailures: [&quot;FAILED_AUTHORIZATION&quot;]</code>
<strong>failed-auth</strong> — the idTag is rejected by the CSMS; StartTransaction is not
attempted. <code>FAILED_AUTHORIZATION</code>
</li>
</ul>

<h3>connector-fault</h3>
<p>
Connector fault during an active session: the connector reports a Faulted status
mid-charging, and the transaction stops with a fault reason.
</p>
<ul>
<li>
<code>expectedFailures: [&quot;CONNECTOR_FAULT&quot;]</code>
<strong>connector-fault</strong> — the connector faults mid-charging and the transaction
stops with a fault reason. <code>CONNECTOR_FAULT</code>
</li>
</ul>

<h3>station-offline</h3>
<p>
Station goes offline during an active session: a StartTransaction is sent but no
StopTransaction follows.
</p>
<ul>
<li>
<code>expectedFailures: [&quot;STATION_OFFLINE_DURING_SESSION&quot;]</code>
<strong>station-offline</strong> — a StartTransaction with no StopTransaction to follow.{' '}
<code>STATION_OFFLINE_DURING_SESSION</code>
</li>
<li>
<strong>meter-value-gap</strong> — an active transaction with no MeterValues between start
and stop. <code>METER_VALUE_GAP</code>
</li>
<li>
<strong>invalid-stop-reason</strong> — a StopTransaction reason not in the OCPP 1.6
specification. <code>INVALID_STOP_REASON</code>
</li>
<li>
<strong>unexpected-start</strong> — a StartTransaction with no preceding BootNotification
or Authorize. <code>UNEXPECTED_START</code>
</li>
<li>
<strong>status-transition-violation</strong> — an invalid OCPP 1.6 connector status
transition (Available directly to Finishing). <code>STATUS_TRANSITION_VIOLATION</code>
</li>
<li>
<strong>diagnostics-failure</strong> — a DiagnosticsStatusNotification reporting
DiagnosisFailed. <code>DIAGNOSTICS_FAILURE</code>
</li>
<li>
<strong>slow-csms-response</strong> — the CSMS takes 15s to answer a BootNotification.{' '}
<code>SLOW_RESPONSE</code>
</li>
<li>
<strong>meter-anomaly</strong> — meter values decrease during a transaction
(non-monotonic). <code>METER_VALUE_ANOMALY</code>
</li>
<li>
<strong>short-session</strong> — a session lasting only ~10 seconds.{' '}
<code>SUSPICIOUS_SESSION_DURATION</code>
</li>
<li>
<strong>heartbeat-irregular</strong> — heartbeats at irregular intervals (300s expected,
600s observed). <code>HEARTBEAT_INTERVAL_VIOLATION</code>
</li>
<li>
<strong>unresponsive-csms</strong> — a Call is sent but the CSMS never answers.{' '}
<code>UNRESPONSIVE_CSMS</code>
</li>
<li>
<strong>unexpected-stop-reason</strong> — a parser/timeline-only fixture (no detection
rule matches) that validates handling of stop events with error payloads.
</li>
</ul>

<h3>unexpected-stop-reason</h3>
<h2>Failure Detection Rules</h2>
<p>
A stop transaction with an unexpected stop reason. This is a parser/timeline-only fixture —
no v0.1 detection rule matches it.
The detection engine implements 16 rules covering the OCPP 1.6J failure taxonomy, ranked by
severity:
</p>
<ul>
<li>
<code>expectedFailures: []</code>
<code>FAILED_AUTHORIZATION</code> — Authorize rejected by the CSMS
</li>
<li>
<code>CONNECTOR_FAULT</code> — connector reports Faulted during an active session
</li>
<li>
<code>STATION_OFFLINE_DURING_SESSION</code> — station drops offline mid-transaction, or a
transaction never stops
</li>
<li>
<code>UNRESPONSIVE_CSMS</code> — a Call is sent but never answered (no CallResult or
CallError)
</li>
<li>
<code>SLOW_RESPONSE</code> — a response exceeds the expected latency budget
</li>
<li>
<code>TIMEOUT_NO_HEARTBEAT</code> — no heartbeat within the expected window
</li>
<li>
<code>HEARTBEAT_INTERVAL_VIOLATION</code> — heartbeats arrive outside the configured
interval
</li>
<li>
<code>REPEATED_BOOT_NOTIFICATION</code> — repeated boots suggest a reboot loop
</li>
<li>
<code>METER_VALUE_GAP</code> — an active transaction with no MeterValues
</li>
<li>
<code>METER_VALUE_ANOMALY</code> — meter values decrease during a transaction
</li>
<li>
<code>STATUS_TRANSITION_VIOLATION</code> — an invalid connector status transition
</li>
<li>
<code>UNEXPECTED_START</code> — a StartTransaction without a preceding boot or authorize
</li>
<li>
<code>INVALID_STOP_REASON</code> — a StopTransaction reason outside the OCPP 1.6 spec
</li>
</ul>

<h2>Failure Detection Rules</h2>
<p>Three detection rules are available in v0.1:</p>
<ul>
<li>
<strong>FAILED_AUTHORIZATION</strong> — Authorize response with
<code>idTagInfo.status = &quot;Invalid&quot;</code>
<code>SUSPICIOUS_SESSION_DURATION</code> — a session ends suspiciously quickly
</li>
<li>
<strong>CONNECTOR_FAULT</strong> — StatusNotification with
<code>status = &quot;Faulted&quot;</code> during an active session
<code>DIAGNOSTICS_FAILURE</code> — a diagnostics upload reports failure
</li>
<li>
<strong>STATION_OFFLINE_DURING_SESSION</strong> — Session has StartTransaction but no
StopTransaction, or connector transitions to Unavailable/Offline during an active
transaction
<code>FIRMWARE_UPDATE_FAILURE</code> — a firmware update reports failure
</li>
</ul>

Expand Down
67 changes: 67 additions & 0 deletions src/app/docs/studio/install/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
export default function StudioInstallPage() {
return (
<div>
<h1>Download &amp; Install Studio</h1>
<p>
OCPP DebugKit Studio is a native desktop app. It is pre-1.0 (0.x) while Zig, the Native SDK,
and the toolkit conformance reference are all pre-1.0.
</p>

<h2>macOS (Apple silicon)</h2>
<p>Paste this into a terminal. It installs the latest Studio into Applications and opens it:</p>
<pre>
<code>{`curl -fsSL https://raw.githubusercontent.com/ocpp-debugkit/studio/main/scripts/install-macos.sh | bash`}</code>
</pre>
<p>
The script downloads the latest release, verifies its SHA-256, installs the app, and
launches it — no toolchain, no manual steps. Prefer to read it first? See{' '}
<a
href="https://github.com/ocpp-debugkit/studio/blob/main/scripts/install-macos.sh"
target="_blank"
rel="noopener noreferrer"
>
<code>scripts/install-macos.sh</code>
</a>
.
</p>

<h2>Linux</h2>
<p>
Download the <code>.tar.gz</code> from the{' '}
<a
href="https://github.com/ocpp-debugkit/studio/releases"
target="_blank"
rel="noopener noreferrer"
>
Releases
</a>{' '}
page, extract it, and run the <code>studio</code> binary. Requires GTK 4 (
<code>libgtk-4</code>, <code>libwebkitgtk-6.0</code>).
</p>

<h2>Build from source</h2>
<p>
Prerequisites: <a href="https://ziglang.org/download/">Zig</a> <code>0.16.0</code> and the
Native SDK CLI (<code>npm install -g @native-sdk/cli</code>).
</p>
<pre>
<code>{`git clone https://github.com/ocpp-debugkit/studio.git
cd studio
native build # produces the release binary`}</code>
</pre>

<h2>All downloads</h2>
<p>
Every release, with checksums and platform assets, is on the{' '}
<a
href="https://github.com/ocpp-debugkit/studio/releases"
target="_blank"
rel="noopener noreferrer"
>
GitHub Releases
</a>{' '}
page.
</p>
</div>
);
}
Loading
Loading