5.5 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Development commands
- Build the app:
go build -o bin/3x-ui.exe ./main.go - Run locally with debug logging:
XUI_DEBUG=true go run ./main.go - Run tests:
go test ./... - Run vet:
go vet ./... - Run a single package test suite:
go test ./path/to/package - Run a single test:
go test ./path/to/package -run TestName - Show CLI help / subcommands:
go run ./main.go --help - Show version:
go run ./main.go -v
VS Code tasks mirror the common Go workflows:
go: buildgo: rungo: testgo: vet
Runtime shape
This is a Go monolith for managing Xray-core, with two Gin-based HTTP servers started from main.go:
- the main panel server in
web/ - the subscription server in
sub/
main.go initializes the SQLite database, starts both servers, and handles process signals:
SIGHUPrestarts the panel + subscription serversSIGUSR1restarts xray-core only
Important: before full shutdown or SIGHUP restart, the Telegram bot is stopped explicitly via service.StopBot() to avoid Telegram 409 conflicts.
High-level architecture
Database and settings
database/db.goinitializes GORM with SQLite, runs auto-migrations, seeds the default admin user, and runs one-time seeders.- Models live in
database/model/model.go. - App configuration is heavily database-backed through the
settingstable rather than static config files. HistoryOfSeedersis used to track one-time migrations such as password hashing changes.
Web panel
web/web.gobuilds the main Gin engine, session middleware, gzip, i18n, static asset serving, template loading, websocket hub setup, and background cron jobs.- Controllers are in
web/controller/. - Business logic lives in
web/service/. - Background tasks live in
web/job/. - The websocket hub is in
web/websocket/and is wired fromweb/web.go.
Subscription server
sub/sub.gostarts a separate Gin server for subscription links and JSON subscriptions.- It has its own listen/port/cert settings and can run independently of the main panel routes.
- It reuses embedded templates/assets from
web/and applies subscription-specific path/domain settings from the database.
Xray integration
xray/is the bridge to xray-core.xray/process.gowritesconfig.json, launches the platform-specific xray binary, tracks process state, and handles stop/restart behavior.xray/api.go,xray/traffic.go, and related files handle API access and traffic/stat collection.- The panel treats xray-core as a managed subprocess and periodically monitors/restarts it from cron jobs in
web/web.go.
Frontend delivery model
- The UI is server-rendered HTML templates plus embedded static assets under
web/html/andweb/assets/. - In production, templates/assets are embedded with
go:embedinweb/web.go. - In debug mode (
XUI_DEBUG=true), templates and assets are loaded from disk, so edits underweb/html/andweb/assets/are reflected without rebuilding embedded resources. - Internationalization files live in
web/translation/*.tomland are initialized byweb/locale.
Background jobs and long-running behavior
web/web.go registers the operational jobs that keep the panel in sync with xray-core. These include:
- xray process health checks
- deferred/statistical traffic collection
- client IP checks / log maintenance
- periodic traffic reset jobs
- optional LDAP sync
- optional Telegram notification and CPU alert jobs
When changing settings or services that affect runtime behavior, check whether a cron job, websocket update, or xray restart path also needs to change.
Repo-specific conventions and gotchas
- Default credentials are seeded as
admin/admin, but stored hashed in the DB. - The app uses DB settings extensively; many behavior changes require updating
SettingService, not just editing route/controller code. - The
Inboundmodel stores much of the Xray config as JSON strings (Settings,StreamSettings,Sniffing), then converts those into xray config structs. - The main panel and subscription server have separate listen/port/cert/base-path concepts. Keep them distinct when changing routing or TLS behavior.
- Session handling uses
gin-contrib/sessionswith a cookie store and secret loaded from settings. - The subscription server intentionally runs Gin in release mode and discards Gin default writers.
- There are currently no
*_test.gofiles in the repo, sogo test ./...mainly validates buildability of packages.
Important files to orient quickly
main.go— process entrypoint, CLI subcommands, signal handlingweb/web.go— main server wiring, embedded assets/templates, cron jobssub/sub.go— subscription server wiringdatabase/db.go— DB init, migrations, seedersdatabase/model/model.go— core persistent modelsweb/service/setting.go— central behavior/settings access pointweb/service/inbound.goandweb/service/xray.go— panel logic tied to xray config/runtimexray/process.go— xray subprocess management
Existing repo guidance carried forward
From .github/copilot-instructions.md and current code structure:
- Treat the project as a Go + Gin + SQLite application with embedded web assets.
- Remember the dual-server design: main panel plus subscription server.
- Preserve the Telegram bot shutdown-before-restart behavior.
- If working on deployment or container behavior, note that Docker support exists via
Dockerfile,DockerInit.sh,DockerEntrypoint.sh, anddocker-compose.yml.