Ana içeriğe geç

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, OcppChargerUpdate
  • OcppSession, OcppMeterSample
  • OcppChargingProfile, OcppLocalAuthListEntry, OcppReservation
  • OcppCommandResponse, OcppErrorEnvelope
  • ProvisioningKitResponse (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)

KategoriSayıÖrnek
Query10useOcppChargers, useOcppCharger, useOcppSessions, useOcppSession, useOcppMeterSamples, useOcppChargingProfiles, useOcppLocalAuthList, useOcppReservations, useOcppProvisioningKitUrl, useOcppChargerStatus
Mutation13useCreateOcppCharger, useUpdateOcppCharger, useDeleteOcppCharger, useRotateOcppPassword, useRemoteStart, useRemoteStop, useReset, useUnlock, useChangeAvailability, useChangeConfig, useTriggerMessage, useUpdateFirmware, useSetChargingProfile (DELETE dahil)
Live Stream1useOcppLiveStream({ chargerId, eventTypes }) — filtered WS subscribe

Sayfa ve Component'ler

PageComponent(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.tsxRegistry: vendor=ZJ-Beny model=BCP-AT2N-P → bu dashboard

Component Detayları

ComponentSorumluluk
ChargerListTableTanStack useOcppChargers + sort/filter + status pill + linkler
NewChargerFormReact Hook Form + Zod (CPID regex, vendor/model/connector_count)
PasswordRevealDialogPassword tek seferlik gösterim, kopyala butonu, PDF download, ESC + outside-click engellenir, onay checkbox zorunlu
TechnicianKitPanelSaha teknisyeni için 6 alan tek görünüm: hostname/port/path/CPID/username/password placeholder
LiveMeterChartRecharts sliding window (60 nokta), Power/Voltage/Current multi-series, ocpp.meter event'lerden besleniyor
ConnectorStatusGridConnector başına status pill, son ocpp.status event'inden güncellenir
ChargerCommandsPanelRemoteStart/Stop/Reset/Unlock/ChangeAvailability/TriggerMessage/UpdateFirmware butonları + permission gating
RecentSessionsTableSon 20 session, status, energy, duration
RecentCommandsLogSon 20 komut, action, status, latency, request_id

Provisioning Akışı

Yeni charger oluşturulduğunda saha kurulum kit'i tek seferde gösterilir:

  1. Admin "Yeni Charger" butonuna tıklarNewChargerForm açılır.
  2. Form gönderilir → backend POST /api/ocpp/chargers çağrısı.
  3. Backend ProvisioningKitResponse döner (password plaintext bir kez).
  4. PasswordRevealDialog açı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ı).
  5. Onay verilince TechnicianKitPanel ile 6 alan ekranda kalır (PDF olmadan da teknisyen okuyabilir).
  6. Sahada teknisyen Beny web UI'a 6 alanı girer (manuel veya PDF'ten).
  7. Charger restart → yeşil pulse LED → ocpp.boot event geldi → liste sayfası useOcppLiveStream ile 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 DLBStatus event'inden)
  • PV surplus oranı (PVStatus event'inden)
  • Faz dengesizliği uyarısı (Voltage L1/L2/L3 spread > %5)

Güvenlik ve A11y

Güvenlik

  • siteConfig.apiUrl/wsUrl zorunlu: 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: ChargerCommandsPanel her buton useHasPermission('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.json
  • locales/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üzenle primary button (ana eylem) + ⋯ Daha Fazla altında RotatePassword ve Delete (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-logs endpoint'inden besleniyor.
    • CommandResultAlert.tsx — komut dialog'unda inline result block (success: yeşil + OCPP Accepted, error: kırmızı + envelope message). Dialog kapatılmadan sonuç görünür.
    • useCommandResultState hook'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) extractErrorMessage helper'ıyla envelope message field'ı 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.tsextractErrorMessage(payload) helper. Envelope message field'ı öncelikli, fallback error_code veya HTTP status. PII guard: id_tag/password/token mesaja 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
1TypeScript typesfrontend/src/types/ocpp.ts
2REST clientfrontend/src/lib/api/ocpp.ts
3WS event consumerfrontend/src/lib/ws/ocpp-events.ts
4TanStack hooksfrontend/src/hooks/useOcppChargers.ts, useOcppLiveStream.ts
5Liste sayfasıfrontend/src/app/chargers/page.tsx
6Yeni charger sayfasıfrontend/src/app/chargers/new/page.tsx
7Detay sayfasıfrontend/src/app/chargers/[id]/page.tsx
8Component'lerfrontend/src/components/chargers/*.tsx
9Beny dashboardfrontend/src/components/device-dashboards/beny-ocpp.tsx
10i18nfrontend/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ü.