Faz 5 — Frontend MVP
PR #267 ile geldi. Zeus admin UI'ında OCPP charger yönetim sayfaları + canlı izleme + provisioning kit modal.
Mimari Katmanlar
+-----------------------------------------------------------+
| frontend/src/ |
| |
| types/ocpp.ts (33 backend mirror) |
| | |
| v |
| lib/api/ocpp.ts (22 endpoint typed REST client) |
| | |
| v |
| lib/ws/ocpp-events.ts (7 OcppEvent discriminated union) |
| | |
| v |
| hooks/useOcppChargers.ts (10 query + 13 mutation) |
| hooks/useOcppLiveStream.ts (WS event filtered subscribe)|
| | |
| v |
| components/chargers/ (UI building blocks) |
| | |
| v |
| app/chargers/ (Next.js App Router pages) |
+-----------------------------------------------------------+
API + WS Layer
TypeScript Types (types/ocpp.ts)
Backend Pydantic schema'larının birebir TypeScript karşılığı (33 type). Faz 3 contract referansı: Faz 3 — REST API.
Önemli tipler:
OcppCharger,OcppChargerCreate,OcppChargerUpdateOcppSession,OcppMeterSampleOcppChargingProfile,OcppLocalAuthListEntry,OcppReservationOcppCommandResponse,OcppErrorEnvelopeProvisioningKitResponse(password bir kez döner)
REST Client (lib/api/ocpp.ts)
22 endpoint typed wrapper, fetcher kullanır (siteConfig.apiUrl zorunlu — CLAUDE.md §2). Her komut çağrısı otomatik Idempotency-Key: crypto.randomUUID() header ekler.
WS Event Consumer (lib/ws/ocpp-events.ts)
7 event tipini TypeScript discriminated union olarak modeller:
type OcppEvent =
| { type: 'ocpp.boot'; ts: string; charger_id: string; data: { ... } }
| { type: 'ocpp.status'; ts: string; charger_id: string; data: { ... } }
| { type: 'ocpp.meter'; ts: string; charger_id: string; data: { ... } }
| { type: 'ocpp.session_started'; ts: string; charger_id: string; data: { ... } }
| { type: 'ocpp.session_stopped'; ts: string; charger_id: string; data: { ... } }
| { type: 'ocpp.command_result'; ts: string; charger_id: string; data: { ... } }
| { type: 'ocpp.firmware_status'; ts: string; charger_id: string; data: { ... } };
TanStack Query Hooks (hooks/useOcppChargers.ts, hooks/useOcppLiveStream.ts)
| Kategori | Sayı | Örnek |
|---|---|---|
| Query | 10 | useOcppChargers, useOcppCharger, useOcppSessions, useOcppSession, useOcppMeterSamples, useOcppChargingProfiles, useOcppLocalAuthList, useOcppReservations, useOcppProvisioningKitUrl, useOcppChargerStatus |
| Mutation | 13 | useCreateOcppCharger, useUpdateOcppCharger, useDeleteOcppCharger, useRotateOcppPassword, useRemoteStart, useRemoteStop, useReset, useUnlock, useChangeAvailability, useChangeConfig, useTriggerMessage, useUpdateFirmware, useSetChargingProfile (DELETE dahil) |
| Live Stream | 1 | useOcppLiveStream({ chargerId, eventTypes }) — filtered WS subscribe |
Sayfa ve Component'ler
| Page | Component(lar) |
|---|---|
app/chargers/page.tsx (liste) | ChargerListTable, ChargerStatusPill, ChargerFilters |
app/chargers/new/page.tsx (yeni kayıt) | NewChargerForm, PasswordRevealDialog, TechnicianKitPanel |
app/chargers/[id]/page.tsx (detay) | ChargerHeader, ChargerCommandsPanel, LiveMeterChart, ConnectorStatusGrid, RecentSessionsTable, RecentCommandsLog |
components/device-dashboards/beny-ocpp.tsx | Registry: vendor=ZJ-Beny model=BCP-AT2N-P → bu dashboard |
Component Detayları
| Component | Sorumluluk |
|---|---|
ChargerListTable | TanStack useOcppChargers + sort/filter + status pill + linkler |
NewChargerForm | React Hook Form + Zod (CPID regex, vendor/model/connector_count) |
PasswordRevealDialog | Password tek seferlik gösterim, kopyala butonu, PDF download, ESC + outside-click engellenir, onay checkbox zorunlu |
TechnicianKitPanel | Saha teknisyeni için 6 alan tek görünüm: hostname/port/path/CPID/username/password placeholder |
LiveMeterChart | Recharts sliding window (60 nokta), Power/Voltage/Current multi-series, ocpp.meter event'lerden besleniyor |
ConnectorStatusGrid | Connector başına status pill, son ocpp.status event'inden güncellenir |
ChargerCommandsPanel | RemoteStart/Stop/Reset/Unlock/ChangeAvailability/TriggerMessage/UpdateFirmware butonları + permission gating |
RecentSessionsTable | Son 20 session, status, energy, duration |
RecentCommandsLog | Son 20 komut, action, status, latency, request_id |
Provisioning Akışı
Yeni charger oluşturulduğunda saha kurulum kit'i tek seferde gösterilir:
- Admin "Yeni Charger" butonuna tıklar →
NewChargerFormaçılır. - Form gönderilir → backend
POST /api/ocpp/chargersçağrısı. - Backend
ProvisioningKitResponsedöner (password plaintext bir kez). PasswordRevealDialogaçılır:- Password gösterilir + "Kopyala" butonu (
navigator.clipboard.writeText). - "PDF İndir" butonu (
/api/ocpp/chargers/{id}/provisioning-kit.pdf) — PDF'te password YAZMAZ, sadece URL alanları + checklist. - "Sahaya not aldım, şifreyi güvenli bir yere kaydettim" onay checkbox'u zorunlu.
- ESC tuşu ve dialog dışına tıklama devre dışı (yanlışlıkla kapatma koruması).
- Password gösterilir + "Kopyala" butonu (
- Onay verilince TechnicianKitPanel ile 6 alan ekranda kalır (PDF olmadan da teknisyen okuyabilir).
- Sahada teknisyen Beny web UI'a 6 alanı girer (manuel veya PDF'ten).
- Charger restart → yeşil pulse LED →
ocpp.bootevent geldi → liste sayfasıuseOcppLiveStreamile otomatik yenilenir.
Detaylı saha akışı: Saha Entegrasyon Kılavuzu — §10 Saha Kurulum Akışı
Live Meter Chart
LiveMeterChart component'i Recharts kullanır:
- Sliding window: Son 60 sample (≈ 30 dk @ 30sn interval).
- Multi-series: Power (kW, primary axis) + Voltage (V) + Current (A).
- Veri kaynağı:
useOcppLiveStream({ chargerId, eventTypes: ['ocpp.meter'] })hook'u. - State:
useReducer— yeni event geldikçe head'e push, tail eski sample'ı pop. - Performans: Component
React.memo+ sample array referans-stabil (immer ile).
Beny OCPP Dashboard
components/device-dashboards/ registry pattern:
DEVICE_DASHBOARD_REGISTRY = {
'ZJ-Beny:BCP-AT2N-P': BenyOcppDashboard,
// diğer cihaz tipleri
};
BenyOcppDashboard özelleştirmesi:
- DLB durumu kartı (vendor DataTransfer
DLBStatusevent'inden) - PV surplus oranı (
PVStatusevent'inden) - Faz dengesizliği uyarısı (Voltage L1/L2/L3 spread > %5)
Güvenlik ve A11y
Güvenlik
siteConfig.apiUrl/wsUrlzorunlu:process.env.NEXT_PUBLIC_*doğrudan kullanılmaz (CLAUDE.md §2 — build-time bake tuzağı).- Password handling: PasswordRevealDialog onay zorunlu, ESC + outside-click engellenir.
- Idempotency-Key UUID otomatik: Her komut mutation'ı
crypto.randomUUID()üretir; React Query retry'ları aynı key ile gönderir. - id_tag son-4 mask: UI hiçbir zaman plaintext id_tag göstermez.
- Permission gating:
ChargerCommandsPanelher butonuseHasPermission('CONTROL_CHARGER')ile koşullu render.
Accessibility
role="status"— live status pill'leri.role="alert"— error toast'ları.- Keyboard navigation: tüm dialog'lar ve table'lar tab-able.
- Color contrast: status renkleri WCAG AA uyumlu (yeşil/mavi/kırmızı + ikon).
i18n
TR + EN parite. Locale dosyaları:
locales/tr/ocpp.jsonlocales/en/ocpp.json
Charger CRUD, komut butonları, status etiketleri, error mesajları, PasswordRevealDialog metinleri her iki dilde mevcut.
UI Refresh (PR-E3, PR-E5 — 2026-04-27)
PR-E entegre planı çerçevesinde frontend katmanında yapılan iyileştirmeler. Backend kontratı değişmedi (PR-E5 yeni endpoint'leri hariç).
PR-E3 — Charger detay + liste UI Refresh (PR #288)
- Header DropdownMenu:
Düzenleprimary button (ana eylem) +⋯ Daha FazlaaltındaRotatePasswordveDelete(yanlışlıkla tıklama koruması; password rotate ve delete iki farklı yıkıcı eylem). - Commands tab kategorize: 3 grup — Şarj (RemoteStart/Stop/Unlock), Yapılandırma (ChangeAvailability/ChangeConfig/SendLocalList), Bakım (Reset/TriggerMessage/UpdateFirmware). Permission gating her buton için aynı kalıyor.
- Liste sayfası: Server-side pagination (URL state
?limit=50&offset=100, F5 sonrası sayfa korunur). Liste kartında status dot + canlı şarj süre/güç chip + inline edit kalem ikonu (modal açmadan name/serial düzenleme). - Overview ek alanlar: subregion, last_heartbeat, OCPP version, vendor/model bilgileri tek bakışta.
PR-E5 — Komut sonuç görünürlüğü (PR #290)
- Yeni component'ler:
CommandLogsPanel.tsx— charger detayda son 20 komut audit trail (action, status, latency, error_message, request_id).GET /chargers/{id}/command-logsendpoint'inden besleniyor.CommandResultAlert.tsx— komut dialog'unda inline result block (success: yeşil + OCPPAccepted, error: kırmızı + envelopemessage). Dialog kapatılmadan sonuç görünür.useCommandResultStatehook'u — 6 dialog'da paylaşılan result state (loading / success / error / idle).
- 6 dialog'da inline result: RemoteStart/Stop/Reset/Unlock/ChangeAvailability/SendLocalList. PR #297 (Hot-fix #4)
extractErrorMessagehelper'ıyla envelopemessagefield'ı düzgün gösteriliyor.
PR-E4 — Tenant-wide RFID kart yönetim sayfası (PR #289)
frontend/src/app/chargers/rfid-cards/page.tsx— tenant geneli RFID kart CRUD (liste, ekle, status/expiry/parent_id_tag güncelle, sil) + seçili charger'lara differential push UI.- Charger-spesifik override
/chargers/{id}/local-auth-list(Faz 3 mevcut) ayrı sayfada kalıyor.
PR-E2 — Region/Subregion charger entegrasyonu (PR #287)
- Charger formu: region → subregion cascade select (region seçilmeden subregion disable).
- Liste sayfası: subregion filter chip; chip kaldırılınca query state temizlenir.
- Detay sayfası: subregion adı clickable (region listing route'una yönlendirir).
Hata görünürlüğü (PR #297 — Hot-fix #4)
frontend/src/lib/api/ocpp.ts—extractErrorMessage(payload)helper. Envelopemessagefield'ı öncelikli, fallbackerror_codeveya HTTP status. PII guard:id_tag/password/tokenmesaja sızdırılmaz.- Sahada gözlenen
Hata: [object Object]regression fix. 6 OCPP komut dialog'unda hata mesajı düzgün Türkçe.
Faz 5 Çıktı Listesi (tamamlandı — PR #267)
| # | İş | Dosya |
|---|---|---|
| 1 | TypeScript types | frontend/src/types/ocpp.ts |
| 2 | REST client | frontend/src/lib/api/ocpp.ts |
| 3 | WS event consumer | frontend/src/lib/ws/ocpp-events.ts |
| 4 | TanStack hooks | frontend/src/hooks/useOcppChargers.ts, useOcppLiveStream.ts |
| 5 | Liste sayfası | frontend/src/app/chargers/page.tsx |
| 6 | Yeni charger sayfası | frontend/src/app/chargers/new/page.tsx |
| 7 | Detay sayfası | frontend/src/app/chargers/[id]/page.tsx |
| 8 | Component'ler | frontend/src/components/chargers/*.tsx |
| 9 | Beny dashboard | frontend/src/components/device-dashboards/beny-ocpp.tsx |
| 10 | i18n | frontend/src/locales/{tr,en}/ocpp.json |
Sonraki: Faz 6 (Session geçmişi UI, raporlar tab, SLD charger node, SmartCharging schedule editor) — bkz. Changelog Roadmap bölümü.