---
name: xray-ui-dev
description: Development and maintenance of Xray Config UI Editor. Use this skill when modifying the React frontend, Zustand store, Xray-core configuration logic, or Remnawave integration.
---

# Xray UI Dev

This skill provides specialized knowledge for developing the Xray Config UI Editor, a static web-based GUI for Xray-core.

## Tech Stack & Workflow

- **Runtime**: Bun (use `bun install`, `bun run dev`, `bun run build`)
- **Frontend**: React 19 (TypeScript), Vite 7
- **Styling**: Tailwind CSS 4
- **State Management**: Zustand 5 + Immer (see `src/store/configStore.ts`)
- **Icons**: Phosphor Icons (`@phosphor-icons/react`)
- **Visuals**: React Flow (`@xyflow/react`) for topology visualization
- **Editor**: CodeMirror 6 (`@codemirror/*`, `@platformos/lang-jsonc`) for JSON/JSONC editing — not Monaco.

## State Management (Zustand)

The application state is managed in `src/store/configStore.ts`.
- Use `useConfigStore` to access the Xray configuration and Remnawave state.
- Most CRUD actions go through the `resolveMutableConfig` helper (parses `rawConfigText`, falls back to `config`) rather than `produce` directly — see that file's actions for the pattern.
- Configuration is persisted in IndexedDB (`src/utils/indexedDbStorage.ts`) under the `xray-config-storage` key, with a one-time migration from legacy `localStorage`. The store exposes `hasHydrated`/`setHasHydrated` — gate any code that reads/writes the store on mount behind `hasHydrated` (see `App.tsx`), since the IndexedDB read is async.

### Common Actions
- `updateSection(section, data)`: Replaces a top-level Xray config section.
- `addItem(section, item)`: Adds an inbound or outbound.
- `updateItem(section, index, item)`: Updates a specific item in a list.
- `saveToRemnawave()`: Pushes the current config to the linked Remnawave profile.

## Xray Configuration Logic

- **Schema**: The hand-authored source of truth is Zod, in `src/core/xray/schemas/**`. A separate JSON Schema (`src/utils/config.schema.json`, auto-generated by `bun run schema:generate` from Xray-core's Go sources) backs the raw-JSON editor's Ajv linter — the two can drift, see the plan doc / recent commits before assuming they agree.
- **Validation**: `src/core/validators/index.ts` (Zod-based; `validateFullConfig` covers the whole config) and `src/core/diagnostics/index.ts` (`runFullDiagnostics`, semantic checks like dangling routing targets). `saveToRemnawave()` and `saveActiveProfile()` in `configStore.ts` both gate on `runFullDiagnostics` critical findings.
- **Protocols**: Supports VMess, VLESS, Trojan, Shadowsocks, Hysteria2, Wireguard, etc.

## UI Components

- **Modals**: Most editing happens in modals located in `src/components/editors/`.
- **UI Elements**: Reusable components are in `src/components/ui/` (Button, Icon, Modal, etc.).
- **Topology**: Traffic flow visualization is in `src/components/topology/`.

## Key Files to Reference

- `src/store/configStore.ts`: Central state and logic.
- `src/utils/config.schema.json`: Auto-generated JSON Schema for the raw-JSON editor's linter (see `scripts/generate-xray-schema.cjs`).
- `src/core/api/remnawave-client.ts`: API client for Remnawave integration.
- `src/core/validators/index.ts`: Zod-based configuration validation logic.
- `src/core/diagnostics/index.ts`: Semantic diagnostics (dangling tags, incompatible flags) that gate save/push.

## Best Practices

1. **Type Safety**: Always maintain strict TypeScript types for Xray config objects.
2. **Immutability**: Use `produce` from `immer` when updating the store to avoid direct state mutation.
3. **Validation**: Add validation logic for new config sections to prevent Xray-core from crashing.
4. **Tailwind 4**: Use modern Tailwind 4 features for styling.
