From 7efa0d9dddcebb20cae19b27eba44965daa929b7 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Sat, 27 Jun 2026 15:42:11 +0200 Subject: [PATCH] docs: add CLAUDE.md agent guides for root and frontend Operational guides the Claude Code CLI auto-loads. The root file covers the stack, repo map, hard rules (no // comments, the endpoints.ts registry, the openapigen StructAllow allowlist, i18n locales, migrations), Go and frontend conventions, and the make verify gate. frontend/CLAUDE.md covers the React + AntD 6 + Vite setup. Both link to CONTRIBUTING.md and frontend/README.md instead of duplicating them, and every claim was fact-checked against the source. --- CLAUDE.md | 101 +++++++++++++++++++++++++++++++++++++++++++++ frontend/CLAUDE.md | 60 +++++++++++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 CLAUDE.md create mode 100644 frontend/CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..93e11b4cd --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,101 @@ +# CLAUDE.md + +Operational guide for AI agents working in this repo. Long-form human docs: +`CONTRIBUTING.md` (setup, testing philosophy) and `frontend/README.md`. +Read those before large changes. This file is the short, must-follow version. + +## Stack +- Backend: Go 1.26 (`module github.com/mhsanaei/3x-ui/v3`), Gin, GORM. + Runs Xray-core as a managed child process (`internal/xray/process.go`) and + imports `github.com/xtls/xray-core` for config types + gRPC stats/handler/router + API. MTProto inbounds run a second managed child — the `mtg` binary + (`internal/mtproto/`) — outside Xray. +- Storage: SQLite by default (`/etc/x-ui/x-ui.db` on Linux; the executable dir on + Windows), PostgreSQL optional (`XUI_DB_TYPE` / `XUI_DB_DSN`). The CGo SQLite + driver (`mattn/go-sqlite3`) needs a C compiler — `CGO_ENABLED=0` builds fail. +- Frontend: React 19 + Ant Design 6 + Vite 8 + TypeScript in `frontend/`, + built into `internal/web/dist/` (gitignored) and embedded via `embed.FS`. + +## Repo map +- `main.go` — entry point + `x-ui` CLI (run, migrate, migrate-db, setting, cert). +- `internal/config/` — env parsing (XUI_DEBUG, XUI_LOG_LEVEL, XUI_LOG_FOLDER, + XUI_BIN_FOLDER, XUI_SKIP_HSTS, XUI_PORT, XUI_DB_*). +- `internal/database/` + `internal/database/model/` — GORM schema (Inbound, + Client, Setting, User), inbound Protocol enum, AutoMigrate + hand-written + migrations in `db.go`. +- `internal/xray/` — Xray child-process lifecycle, config generation, gRPC API. +- `internal/mtproto/` — MTProto inbounds via the bundled `mtg` binary. +- `internal/sub/` — subscription server (raw / JSON / Clash). +- `internal/eventbus/` — in-process pub/sub (outbound/node health, xray.crash, + cpu.high, memory.high, login.attempt). +- `internal/logger/`, `internal/util/` (link, crypto, sys, ldap, …), + `internal/tunnelmonitor/` — shared infrastructure. +- `internal/web/` — Gin server (embeds `dist/` + `translation/`). + - `controller/` — panel + REST API handlers; OpenAPI at /panel/api/openapi.json. + - `service/` — business logic (InboundService, SettingService, XrayService, + node sync); subpackages tgbot/, email/, outbound/, panel/, integration/. + - `job/` — cron jobs (traffic, fail2ban IP-limit, node heartbeat/sync, LDAP). + - `middleware/`, `entity/`, `global/`, `session/` (CSRF), `network/`, + `runtime/` (master/sub-node over mTLS), `websocket/`. + - `locale/` + `translation/` — i18n, 13 embedded locale JSON files. +- `frontend/` — React + TS source (see `frontend/CLAUDE.md`). +- `tools/openapigen/` — Go generator that emits frontend types + Zod/JSON schemas + into `frontend/src/generated/` from Go structs. The OpenAPI doc itself + (`frontend/public/openapi.json`) is assembled from those + `endpoints.ts` by + `frontend/scripts/build-openapi.mjs`. + +## Hard rules (non-negotiable) +- NO `//` line comments in committed Go/TS. Names carry meaning; rename instead + of annotating. Exempt: `//go:build`, `//go:generate`, and other directives. + HTML `` is fine. (A linter cannot enforce this — you must.) +- New `g.POST`/`g.GET` in `internal/web/controller/` REQUIRES a matching entry + in `frontend/src/pages/api-docs/endpoints.ts`, then `make gen` (or + `cd frontend && npm run gen`). It is a hand-maintained registry — nothing checks + it against the Go routes, so an omitted route silently vanishes from the docs. +- Response examples come from Go struct `example:` tags via `tools/openapigen` — + never hand-write them. A new struct must be added to openapigen's `StructAllow` + allowlist (`tools/openapigen/main.go`) or it is silently omitted from + schemas/examples (and `build-openapi.mjs` then fails on the missing schema). +- A new English i18n key must be added to EVERY locale JSON in + `internal/web/translation/` (13 files). Missing keys fall back to en-US (or + render the raw key if absent there too); nothing fails the build, so they are + easy to miss. +- DB / model changes require a migration in `internal/database/db.go`. +- Conventional-commit prefixes (`feat`, `fix`, `refactor`, `chore`, `docs`, + `style`): `: short imperative summary`, then a body explaining the why. + +## Go conventions +- Stdlib `testing` only (no testify). Table-driven, `t.Run` subtests, + `t.Helper()` on helpers. Assert the exact value / typed error / emitted + string, never just `err != nil`. Prefer real deps over mocks: throwaway DB via + `database.InitDB(filepath.Join(t.TempDir(), "x-ui.db"))` + + `t.Cleanup(func() { _ = database.CloseDB() })`; `httptest` for HTTP. + `internal/sub`'s `initSubDB(t)` is the template. +- Code must pass `golangci-lint run` (gofumpt + goimports formatting): `make lint`. + +## Frontend conventions (summary; full version in frontend/CLAUDE.md) +- Ant Design 6 only — no Tailwind/shadcn. Targeted tweaks, not rewrites. +- TS strict; `@typescript-eslint/no-explicit-any` is an error. Zod schemas in + `src/schemas/` are the source of truth; infer types with `z.infer`, never + hand-write. Do not edit `src/generated/`. +- Editing `frontend/src` does NOT change what users see until the Vite build is + regenerated into `internal/web/dist/`. In `XUI_DEBUG=true`, HTML is served from + the frozen embedded FS but JS/CSS off disk — after `npm run build` you MUST + restart `go run .` or you get a blank page with 404s. +- After touching share-link logic (`src/lib/xray/`), run `npm run test` (golden + fixtures); regenerate snapshots (`npx vitest run -u`) only for intentional + output changes, never to make a red test green. + +## Build, test, verify +Run `make help` for all targets. The full local gate that mirrors CI: + + make verify + +Common targets: `make gen` (regenerate Zod/OpenAPI), `make lint` (Go + frontend), +`make test` (Go `-shuffle=on` + frontend), `make race`, `make build`. See `Makefile`. + +## Definition of done (before opening a PR) +1. `make gen` and confirm `git diff` on `frontend/src/generated` + + `frontend/public/openapi.json` is clean. +2. `make verify` passes. +3. Diff is focused; refactors are separate from feature work. diff --git a/frontend/CLAUDE.md b/frontend/CLAUDE.md new file mode 100644 index 000000000..e5c43450f --- /dev/null +++ b/frontend/CLAUDE.md @@ -0,0 +1,60 @@ +# frontend/CLAUDE.md + +Frontend agent guide. Full detail: `frontend/README.md` and the root +`CONTRIBUTING.md` ("Working on the frontend"). This is the short version. + +## What this is +React 19 + Ant Design 6 + Vite 8 + TypeScript. The Vite config is +`vite.config.js` (plain JS). Three bundles, each emitted into +`internal/web/dist/` and embedded into the Go binary: +- `index.html` — admin panel SPA (entry `src/main.tsx`; react-router under + `/panel`, lazy routes). +- `login.html` — login + 2FA (`src/entries/login.tsx`). +- `subpage.html` — public subscription viewer (`src/entries/subpage.tsx`). +The `@` import alias maps to `src/`. + +## Data flow +- Server state via TanStack Query (`src/api/`, keys in `src/api/queryKeys.ts`); + invalidate on mutation. WebSocket pushes feed the cache + (`src/api/websocketBridge.ts`). +- Local UI state in the page (`useState`); shared concerns via `src/hooks/`. + Extend an existing hook before adding a global. +- Zod (`src/schemas/`) is the single source of truth for the xray config model. + Infer types with `z.infer`. Go-side types are mirrored into `src/generated/` + by `npm run gen:zod` (`go run ./tools/openapigen`) — do not hand-edit that + folder (every file is marked `DO NOT EDIT`). +- xray domain logic (links, defaults, form<->wire adapters) is pure functions in + `src/lib/xray/`. HTTP goes through `HttpUtil` in `src/utils/index.ts`. + +## Rules +- Ant Design 6 only; no Tailwind/shadcn (a migration was rolled back). +- Function components + hooks only; no class components. +- No `//` line comments in committed TS/TSX. HTML comments are fine. +- TS strict; `no-explicit-any` is an error. Validate form fields with + `antdRule(Schema.shape.field, t)` from `@/utils/zodForm`, not inline + `z.string()`. +- New `g.POST`/`g.GET` route => add it to `src/pages/api-docs/endpoints.ts`, + then `npm run gen`. +- i18n strings live in `internal/web/translation/.json`, NOT under + `frontend/`, and are shared with the Go backend. A new English key must be + added to every locale. Interpolation here uses single braces `{var}`, not the + i18next default `{{var}}`. +- Persian/Arabic (RTL) users are first-class — isolate code identifiers on their + own line when writing Persian text in labels/toasts. +- Vite is pinned to an exact version (no `^`) — bump deliberately, then verify + `npm run dev` AND `npm run build`. + +## Adding a panel route +1. `src/pages//.tsx` (kebab folder, PascalCase component). +2. Register in `src/routes.tsx` under `/panel` (lazy import). +3. Add a sidebar link in `src/layouts/AppSidebar.tsx` if it needs nav. +Only standalone bundles (login/subpage) need a new `.html` + `src/entries/*` + +`rollupOptions.input` (in `vite.config.js`) + a Go controller route. + +## Commands +- `npm run dev` (HMR on :5173, proxies to the Go panel on :2053 — start Go first). +- `npm run typecheck` / `npm run lint` / `npm run test` / `npm run build`. +- `npm run gen` = `gen:zod` (Go → `src/generated/`) + `gen:api` + (`build-openapi.mjs` → `public/openapi.json`). +- After `npm run build`, RESTART `go run .` (see the XUI_DEBUG gotcha in root + CLAUDE.md) before checking the panel.