Skip to main content

Web UI

Overview​

DR-Syncer includes an optional web dashboard deployed on the control cluster for monitoring replication status, managing CRDs, and triggering DR operations — without needing kubectl access.

The Web UI is a separate deployment (own pod, own Docker image) consisting of a Go API server (Chi router) that serves both a REST API and an embedded React single-page application.

Architecture​

+---------------------------------------------------+
| Web UI Pod |
| +---------------------------------------------+ |
| | Go API Server (Chi) | |
| | :8443 --- REST API + WebSocket | |
| | :8080 --- Prometheus metrics | |
| | :8081 --- Health probes | |
| +---------------------------------------------+ |
| +---------------------------------------------+ |
| | Embedded React SPA (static files) | |
| +---------------------------------------------+ |
+---------------------------------------------------+
| |
K8s API GitHub OAuth
(CRDs, Secrets) (external)

Components​

  • Go API Server: Chi router serving REST endpoints for CRD CRUD, DR operations, user management, and WebSocket for real-time updates
  • React Frontend: Vite + React + TypeScript + shadcn/ui embedded in the Go binary via embed.FS
  • Authentication: Local auth (K8s Secret-backed) + GitHub OAuth2, JWT tokens (15min access + 7d refresh)
  • WebSocket: Real-time CRD status updates pushed from K8s informers to connected clients

Features​

Dashboard​

  • Cluster connectivity status (health indicators)
  • Active sync operations with real-time progress bars
  • Recent operation history
  • Quick-action buttons for common DR operations

CRD Management​

  • Full CRUD for NamespaceMappings, ClusterMappings, BackupRepositories
  • Read-only views for RemoteClusters, PVCSyncOperations, VolumeBackupOperations
  • Real-time status updates via WebSocket

DR Operations​

  • Trigger Stage, Cutover, and Failback operations from the UI
  • Wizard-style flow: Select mapping -> Choose operation -> Confirm -> Live progress
  • Real-time log output and cancel support

User Management​

  • Local users stored in K8s Secret with bcrypt password hashing
  • GitHub OAuth2 single sign-on
  • Three RBAC roles: Admin, Operator, Viewer

Authentication​

Local Auth​

Users are stored in a K8s Secret (dr-syncer-ui-users) in the dr-syncer-system namespace. The secret contains a users.json key with user records including username, bcrypt hash, and role.

The user list is cached in-memory on startup and hot-reloaded via a K8s informer watch on the Secret.

GitHub OAuth​

Standard OAuth2 Authorization Code flow. GitHub users must be pre-provisioned in the local user store (matched by GitHub user ID). No auto-provisioning in v1.

JWT Tokens​

  • Access token: 15-minute expiry, contains user ID, username, and role
  • Refresh token: 7-day expiry, stored server-side
  • Signing: HS256 with a secret stored in K8s Secret dr-syncer-ui-jwt-secret

RBAC​

RoleCRD ReadCRD WriteTrigger OpsUser Mgmt
ViewerYesNoNoNo
OperatorYesYesYesNo
AdminYesYesYesYes

Configuration​

Enabling the Web UI​

# values.yaml
ui:
enabled: true
replicaCount: 1
image:
repository: docker.io/supporttools/dr-syncer-ui
tag: "latest"
service:
type: ClusterIP
port: 8443
ingress:
enabled: false
className: ""
hosts:
- host: dr-syncer.example.com
paths:
- path: /
pathType: Prefix
tls: []
auth:
jwtSecret: "" # Auto-generated if empty
github:
enabled: false
clientID: ""
clientSecret: ""
allowedOrgs: [] # Restrict to specific GitHub orgs
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi

Accessing the UI​

With the default ClusterIP service:

kubectl port-forward svc/dr-syncer-ui -n dr-syncer-system 8443:8443
# Open https://localhost:8443

With Ingress enabled, access via the configured hostname.

Default Admin User​

On first startup, if no user Secret exists, the UI server creates a default admin user:

  • Username: admin
  • Password: admin (change immediately)

API Endpoints​

Public​

MethodPathDescription
POST/api/v1/auth/loginLocal login (username/password -> JWT)
POST/api/v1/auth/refreshRefresh access token
GET/api/v1/auth/githubInitiate GitHub OAuth flow
GET/api/v1/auth/github/callbackGitHub OAuth callback
POST/api/v1/auth/logoutInvalidate refresh token

Authenticated (JWT Required)​

MethodPathDescriptionMin Role
GET/api/v1/meCurrent user infoViewer
GET/api/v1/clustersList RemoteClustersViewer
GET/POST/PUT/DELETE/api/v1/namespace-mappingsNamespaceMapping CRUDOperator (write)
GET/POST/PUT/DELETE/api/v1/cluster-mappingsClusterMapping CRUDOperator (write)
GET/api/v1/pvc-sync-opsList PVCSyncOperationsViewer
GET/POST/PUT/DELETE/api/v1/backup-reposBackupRepository CRUDOperator (write)
GET/api/v1/volume-backup-opsList VolumeBackupOperationsViewer
POST/api/v1/operations/stageTrigger StageOperator
POST/api/v1/operations/cutoverTrigger CutoverOperator
POST/api/v1/operations/failbackTrigger FailbackOperator
GET/POST/PUT/DELETE/api/v1/usersUser managementAdmin
WS/api/v1/wsReal-time CRD updatesViewer

Real-Time Updates​

The WebSocket endpoint at /api/v1/ws provides real-time CRD change notifications. Messages follow this format:

{
"type": "crd_update",
"resource": "namespacemapping",
"action": "modified",
"data": { ... }
}

The frontend uses these events to update the TanStack Query cache directly, providing instant UI updates without polling.

Tech Stack​

Backend​

  • Go + Chi router (net/http compatible)
  • K8s client-go (dynamic + typed clients)
  • gorilla/websocket for WebSocket
  • golang-jwt for JWT tokens
  • golang.org/x/oauth2 for GitHub OAuth

Frontend​

  • Vite + React 18 + TypeScript
  • shadcn/ui (Tailwind CSS + Radix UI)
  • TanStack Query v5 (server state)
  • Zustand (client state)
  • React Router v6
  • React Hook Form + Zod (form validation)
  • Recharts (metrics visualization)