diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3c86c5a73..0b30aedfe 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -186,7 +186,7 @@ Only a genuinely **standalone bundle** (like `login` or `subpage`, reachable wit - **Function components + hooks** everywhere. No class components. - **Comments in committed Go/TS/TSX: 2 lines MAX per comment block**, spent on the *why* a name cannot hold — an invariant, an issue number, a non-obvious constraint. Names should carry the meaning; rename rather than annotate. Compiler and tool directives (`//go:build`, `//go:generate`, `//nolint:`) are exempt, and HTML `` is fine for template structure. - **Persian and Arabic users are first-class.** When writing Persian text in toasts or labels, isolate code identifiers on their own lines so RTL reading flows. (Full RTL layout is not currently wired through AntD `ConfigProvider direction` — only the Jalali date picker is RTL-aware — so treat RTL as an open area, not a solved one.) -- **Schemas over `any`.** New config shapes go in `src/schemas/`; oxlint's `typescript/no-explicit-any` is an error and production schemas use no `.loose()`. Validate form fields with `antdRule(Schema.shape.field, t)` rather than inline `z.string()` in rules. +- **Schemas over `any`.** New config shapes go in `src/schemas/`; oxlint's `typescript/no-explicit-any` is an error and production schemas use no `.loose()`. Validate form fields with `rules={{ validate: rhfZodValidate(Schema.shape.field) }}` rather than inline `z.string()` in rules. - **Document new endpoints.** Every new `g.POST`/`g.GET` in `internal/web/controller/` needs a matching entry in `src/pages/api-docs/endpoints.ts` — it drives both the in-panel API docs and the generated OpenAPI/Zod (`npm run gen:api` / `gen:zod`). - **Do not break link generation.** Share-link logic lives in `src/lib/xray/` (`inbound-link.ts`, `outbound-link-parser.ts`, …) and is round-tripped by the golden fixture suite — run `npm run test` after any change to URL generation, defaults, or TLS/Reality handling, and regenerate snapshots (`npx vitest run -u`) only for intentional changes. Two runtime paths consume it: the **inbounds page** and the **clients page** subscription links (`/panel/api/clients/subLinks/:subId` → backend `GetSubs`); exercise both. - **Vite is pinned to an exact version** (no `^`) in `frontend/package.json` — read the live version there rather than trusting a number quoted here — so local, CI, and release builds resolve identically. Bump it deliberately and verify both `npm run dev` and `npm run build` afterward. diff --git a/frontend/CLAUDE.md b/frontend/CLAUDE.md index 6ddf48e4a..cf0ac2108 100644 --- a/frontend/CLAUDE.md +++ b/frontend/CLAUDE.md @@ -33,11 +33,12 @@ The `@` import alias maps to `src/`. - Function components + hooks only; no class components. - Comments in committed TS/TSX: 2 lines MAX per comment block, spent on the *why* a name cannot hold (same rule as root CLAUDE.md). HTML comments are fine. -- TS strict; oxlint's `typescript/no-explicit-any` is an error. Build forms with `useZodForm` + - `FormField` from `@/components/form/rhf` (wrap the tree in `FormProvider`); - validate through the `zodResolver` or per-field +- TS strict; oxlint's `typescript/no-explicit-any` is an error. Build forms with React Hook + Form's `useForm` + `FormField` from `@/components/form/rhf` (wrap the tree in + `FormProvider`) and validate each field with `rules={{ validate: rhfZodValidate(Schema.shape.field) }}` — messages are Zod - issue keys resolved via `t()`, never inline `z.string()`. AntD `