- **Naming**: camelCase for variables/functions/methods, PascalCase for classes/types/enums/interfaces, SCREAMING_SNAKE_CASE for all constants (production and test)
- **Constant unit suffixes**: Time/size constants MUST include unit in name: `_MS`, `_SECONDS`, `_BYTES`. Counts/ratios/strings: no suffix. No inline `// Ms` comments — the name IS the documentation
-- **Async**: Prefer async/await over raw Promises; fire-and-forget wrapped in `void`; handle rejections with try/catch
+- **Async**: Use async/await only for genuinely asynchronous operations. Do not wrap synchronous code in Promises or mark methods `async` without `await`. Fire-and-forget wrapped in `void`; handle rejections with try/catch. Interface methods return `Promise` only when at least one implementation is genuinely async (e.g., `AuthStrategy.authenticate()` — remote strategy does network I/O)
- **Error handling**: Typed errors (`BaseError`, `OCPPError`) with structured properties; avoid generic `Error`; use `instanceof` guards (not `as` casts)
-- **`new Error()` in utils/ and worker/**: Acceptable — `BaseError` lives in `exception/` which cannot be imported from utils (see Common Pitfalls)
+- **`new Error()` in utils/, worker/, and auth/cache/**: Acceptable — `BaseError` lives in `exception/` which cannot be imported from these modules without circular dependencies (see Common Pitfalls)
- **Null safety**: Avoid non-null assertions (`!`); use optional chaining (`?.`) and nullish coalescing (`??`)
- **Type safety**: Prefer explicit types over `any`; use type guards and discriminated unions; no `as any`, `@ts-ignore`, `@ts-expect-error`
## Design Patterns
-| Pattern | Where | Detail |
-| -------------------- | --------------------------------------------------------------- | --------------------------------------------------------------- | ---------- |
-| Singleton | Bootstrap, Configuration, PerformanceStatistics, UIClient (Vue) | Lazy `getInstance()` |
-| Strategy | Auth subsystem | Local/Remote/Certificate strategies with priority chain |
-| Factory | WorkerFactory, StorageFactory, AuthComponentFactory | Create implementations from config |
-| EventEmitter | ChargingStation, Bootstrap | State change events |
-| SRPC | UI WebSocket | `[uuid, procedureName, payload]` request/response correlation |
-| Barrel exports | All components | `index.ts` re-exports public API |
-| Discriminated unions | OCPP types | `BootNotificationRequest = OCPP16... | OCPP20...` |
-| `as const` merge | OCPP enums | `ConnectorStatusEnum = { ...OCPP16..., ...OCPP20... } as const` |
+| Pattern | Where | Detail |
+| -------------------- | --------------------------------------------------------------- | ---------------------------------------------------------------------- |
+| Singleton | Bootstrap, Configuration, PerformanceStatistics, UIClient (Vue) | Lazy `getInstance()` |
+| Strategy | Auth subsystem | Local/Remote/Certificate strategies with priority chain |
+| Factory | WorkerFactory, StorageFactory, AuthComponentFactory | Create implementations from config |
+| EventEmitter | ChargingStation, Bootstrap | State change events |
+| SRPC | UI WebSocket | `[uuid, procedureName, payload]` request/response correlation |
+| Barrel exports | All components | `index.ts` re-exports public API |
+| Discriminated unions | OCPP types | `BootNotificationRequest = OCPP16BootNotificationRequest \| OCPP20...` |
+| `as const` merge | OCPP enums | `ConnectorStatusEnum = { ...OCPP16..., ...OCPP20... } as const` |
## Auth Subsystem (`ocpp/auth/`)
- **OCPPAuthServiceImpl**: Strategy priority chain (local → remote → certificate)
-- **3 strategies**: LocalAuthStrategy (cache + local list), RemoteAuthStrategy (CSMS), CertificateAuthStrategy (X.509)
+- **3 strategies**: LocalAuthStrategy (cache + local auth list lookup), RemoteAuthStrategy (CSMS network calls), CertificateAuthStrategy (X.509)
- **InMemoryAuthCache**: LRU with TTL, rate limiting, periodic cleanup
-- **AuthComponentFactory**: Creates adapters, strategies, caches with DI
+- **InMemoryLocalAuthListManager**: CSMS-managed authorization list with Full/Differential updates, version tracking, capacity limits
+- **AuthComponentFactory**: Creates adapters, strategies, caches, managers from config
+- **AuthHelpers**: Cross-version utility functions (TTL calculation, config key reading, result formatting)
- **Version adapters**: OCPP16AuthAdapter, OCPP20AuthAdapter
## UI Server (`ui-server/`)
Gated steps (lint, typecheck, coverage, SonarCloud) run only on the gated platform. Build + test run on all platforms.
+## OCPP Specification Documents (`docs/`)
+
+```
+docs/
+├── ocpp16/ # OCPP 1.6 specs, errata, security whitepaper, JSON schemas
+├── ocpp2/ # OCPP 2.0.1 specs, test cases, certification profiles
+├── ocpp21/ # OCPP 2.1 specs, errata, appendices
+└── signed_meter_values-v10-1.md
+```
+
+24 markdown files covering all supported OCPP versions. Authoritative spec references for implementing OCPP commands. Indexed in QMD as `ocpp-specs` collection (see `suggested_commands` memory for search commands).
+
## Key Dependencies
- **ws** — WebSocket client/server
---
+## OCPP Spec Search (QMD)
+
+`docs/` is indexed as QMD collection `ocpp-specs` (24 markdown files, 3213 chunks).
+
+```bash
+# BM25 keyword search (always works)
+qmd search "D01.FR SendLocalList requirements" --collections ocpp-specs
+
+# Hybrid search with LLM expand + rerank (needs env -u CI in agent context)
+env -u CI qmd query "what happens when LocalAuthListEnabled is disabled" --collections ocpp-specs
+
+# Vector similarity only
+qmd vsearch "functional requirements for local authorization list" --collections ocpp-specs
+```
+
+Re-index after spec updates: `qmd update --pull && qmd embed`
+
+**Setup**: QMD stores absolute paths. Use a stable path:
+
+```bash
+qmd collection add /Users/I339261/SAPDevelop/e-mobility-charging-stations-simulator-git/docs --name ocpp-specs
+qmd embed
+```
+
+---
+
## Docker
```bash