diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index d99079e80e..af34971d46 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -16,6 +16,50 @@ This is a React-based monitoring and management interface for YDB clusters. The - Use React Router v5 (NOT v6) for routing - Use Monaco Editor 0.52 for code editing features +## Critical Bug Prevention Patterns + +### React Performance (MANDATORY) + +- **ALWAYS** use `useMemo` for expensive computations, object/array creation +- **ALWAYS** use `useCallback` for functions in effect dependencies +- **ALWAYS** memoize table columns, filtered data, computed values +- **AVOID** `useEffect` when possible - prefer direct approaches with `useCallback` +- **PREFER** direct event handlers and callbacks over useEffect for user interactions + +```typescript +// ✅ REQUIRED patterns +const displaySegments = useMemo(() => segments.filter((segment) => segment.visible), [segments]); +const handleClick = useCallback(() => { + // logic +}, [dependency]); + +// ✅ PREFER direct callbacks over useEffect +const handleInputChange = useCallback( + (value: string) => { + setSearchTerm(value); + onSearchChange?.(value); + }, + [onSearchChange], +); + +// ❌ AVOID unnecessary useEffect +// useEffect(() => { +// onSearchChange?.(searchTerm); +// }, [searchTerm, onSearchChange]); +``` + +### Memory & Display Safety + +- **ALWAYS** provide fallback values: `Number(value) || 0` +- **NEVER** allow division by zero: `capacity > 0 ? value/capacity : 0` +- **ALWAYS** dispose Monaco Editor: `return () => editor.dispose();` in useEffect + +### Security & Input Validation + +- **NEVER** expose authentication tokens in logs or console +- **ALWAYS** validate user input before processing +- **NEVER** skip error handling for async operations + ## Critical Coding Rules ### API Architecture @@ -88,18 +132,50 @@ This is a React-based monitoring and management interface for YDB clusters. The - Use React Router v5 hooks (`useHistory`, `useParams`) - Always validate route params exist before use +### URL Parameter Management (MANDATORY) + +- **PREFER** `use-query-params` over `redux-location-state` for new development +- **ALWAYS** use Zod schemas for URL parameter validation with fallbacks +- **ALWAYS** use `z.enum([...]).catch(defaultValue)` pattern for safe parsing +- Use custom `QueryParamConfig` objects for encoding/decoding complex parameters + +```typescript +// ✅ REQUIRED pattern for URL parameters +const sortColumnSchema = z.enum(['column1', 'column2', 'column3']).catch('column1'); + +const SortOrderParam: QueryParamConfig = { + encode: (value) => (value ? encodeURIComponent(JSON.stringify(value)) : undefined), + decode: (value) => { + try { + return value ? JSON.parse(decodeURIComponent(value)) : []; + } catch { + return []; + } + }, +}; +``` + ## Common Utilities - Formatters: `formatBytes()`, `formatDateTime()` from `src/utils/dataFormatters/` - Time parsing: utilities in `src/utils/timeParsers/` - Query utilities: `src/utils/query.ts` for SQL/YQL helpers +## Development Commands + +```bash +npm run lint # Run all linters before committing +npm run typecheck # TypeScript type checking +npm run unused # Find unused code +``` + ## Before Making Changes - Run `npm run lint` and `npm run typecheck` before committing - Follow conventional commit message format - Use conventional commit format for PR titles with lowercase subjects (e.g., "fix: update api endpoints", "feat: add new component", "chore: update dependencies") - PR title subjects must be lowercase (no proper nouns, sentence-case, start-case, pascal-case, or upper-case) +- PR title must not exceed 72 characters (keep them concise and descriptive) - Ensure all user-facing text is internationalized - Test with a local YDB instance when possible @@ -108,3 +184,10 @@ This is a React-based monitoring and management interface for YDB clusters. The - `window.api` - Access API methods in browser console - `window.ydbEditor` - Monaco editor instance - Enable request tracing with `DEV_ENABLE_TRACING_FOR_ALL_REQUESTS` + +## Environment Variables + +- `REACT_APP_BACKEND` - Backend URL for single-cluster mode +- `REACT_APP_META_BACKEND` - Meta backend URL for multi-cluster mode +- `PUBLIC_URL` - Base URL for static assets (use `.` for relative paths) +- `GENERATE_SOURCEMAP` - Set to `false` for production builds diff --git a/AGENTS.md b/AGENTS.md index 087f56963c..22b00c12c1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -91,6 +91,57 @@ src/ 3. **Feature-based Organization**: Features grouped with their state, API, and components 4. **Separation of Concerns**: Clear separation between UI and business logic +## Critical Bug Prevention Patterns + +### Memory Management + +- **ALWAYS** dispose Monaco Editor instances: `return () => editor.dispose();` in useEffect +- **NEVER** allow memory leaks in long-running components +- Clear timeouts and intervals in cleanup functions + +### React Performance (MANDATORY) + +- **ALWAYS** use `useMemo` for expensive computations and object/array creation +- **ALWAYS** use `useCallback` for functions passed to dependencies +- **ALWAYS** memoize table columns, filtered data, and computed values +- **AVOID** `useEffect` when possible - prefer direct approaches with `useCallback` +- **PREFER** direct event handlers and callbacks over useEffect for user interactions + +```typescript +// ✅ REQUIRED patterns +const displaySegments = useMemo(() => segments.filter((segment) => segment.visible), [segments]); +const handleClick = useCallback(() => { + // logic +}, [dependency]); + +// ✅ PREFER direct callbacks over useEffect +const handleInputChange = useCallback( + (value: string) => { + setSearchTerm(value); + onSearchChange?.(value); + }, + [onSearchChange], +); + +// ❌ AVOID unnecessary useEffect +// useEffect(() => { +// onSearchChange?.(searchTerm); +// }, [searchTerm, onSearchChange]); +``` + +### Display Safety + +- **ALWAYS** provide fallback values: `Number(value) || 0` +- **NEVER** allow division by zero: `capacity > 0 ? value/capacity : 0` +- **ALWAYS** handle null/undefined data gracefully + +### Security & Input Validation + +- **NEVER** expose authentication tokens in logs or console output +- **ALWAYS** validate user input before processing +- **NEVER** skip error handling for async operations +- Sanitize data before displaying in UI components + ## Important Development Notes ### Testing Backend Connection @@ -216,6 +267,31 @@ Complex modals use `@ebay/nice-modal-react` library. Simple dialogs use Gravity Uses React Router v5 hooks (`useHistory`, `useParams`, etc.). Always validate route params exist before using them. +### URL Parameter Management + +- **PREFER** `use-query-params` over `redux-location-state` for new development +- **ALWAYS** use Zod schemas for URL parameter validation with fallbacks +- Use custom `QueryParamConfig` objects for encoding/decoding complex parameters +- Use `z.enum([...]).catch(defaultValue)` pattern for safe parsing with fallbacks + +```typescript +// ✅ PREFERRED pattern for URL parameters +const sortColumnSchema = z.enum(['column1', 'column2', 'column3']).catch('column1'); + +const SortOrderParam: QueryParamConfig = { + encode: (value) => (value ? encodeURIComponent(JSON.stringify(value)) : undefined), + decode: (value) => { + try { + return value ? JSON.parse(decodeURIComponent(value)) : []; + } catch { + return []; + } + }, +}; + +const [urlParam, setUrlParam] = useQueryParam('sort', SortOrderParam); +``` + ### Critical Rules - **NEVER** call APIs directly - use `window.api.module.method()` @@ -226,6 +302,8 @@ Uses React Router v5 hooks (`useHistory`, `useParams`, etc.). Always validate ro - **ALWAYS** handle loading states in UI - **ALWAYS** validate route params exist before use - **ALWAYS** follow i18n naming rules from `i18n-naming-ruleset.md` +- **ALWAYS** use Zod schemas for URL parameter validation with fallbacks +- **PREFER** `use-query-params` over `redux-location-state` for new URL parameter handling ### Debugging Tips diff --git a/CLAUDE.md b/CLAUDE.md index 087f56963c..22b00c12c1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -91,6 +91,57 @@ src/ 3. **Feature-based Organization**: Features grouped with their state, API, and components 4. **Separation of Concerns**: Clear separation between UI and business logic +## Critical Bug Prevention Patterns + +### Memory Management + +- **ALWAYS** dispose Monaco Editor instances: `return () => editor.dispose();` in useEffect +- **NEVER** allow memory leaks in long-running components +- Clear timeouts and intervals in cleanup functions + +### React Performance (MANDATORY) + +- **ALWAYS** use `useMemo` for expensive computations and object/array creation +- **ALWAYS** use `useCallback` for functions passed to dependencies +- **ALWAYS** memoize table columns, filtered data, and computed values +- **AVOID** `useEffect` when possible - prefer direct approaches with `useCallback` +- **PREFER** direct event handlers and callbacks over useEffect for user interactions + +```typescript +// ✅ REQUIRED patterns +const displaySegments = useMemo(() => segments.filter((segment) => segment.visible), [segments]); +const handleClick = useCallback(() => { + // logic +}, [dependency]); + +// ✅ PREFER direct callbacks over useEffect +const handleInputChange = useCallback( + (value: string) => { + setSearchTerm(value); + onSearchChange?.(value); + }, + [onSearchChange], +); + +// ❌ AVOID unnecessary useEffect +// useEffect(() => { +// onSearchChange?.(searchTerm); +// }, [searchTerm, onSearchChange]); +``` + +### Display Safety + +- **ALWAYS** provide fallback values: `Number(value) || 0` +- **NEVER** allow division by zero: `capacity > 0 ? value/capacity : 0` +- **ALWAYS** handle null/undefined data gracefully + +### Security & Input Validation + +- **NEVER** expose authentication tokens in logs or console output +- **ALWAYS** validate user input before processing +- **NEVER** skip error handling for async operations +- Sanitize data before displaying in UI components + ## Important Development Notes ### Testing Backend Connection @@ -216,6 +267,31 @@ Complex modals use `@ebay/nice-modal-react` library. Simple dialogs use Gravity Uses React Router v5 hooks (`useHistory`, `useParams`, etc.). Always validate route params exist before using them. +### URL Parameter Management + +- **PREFER** `use-query-params` over `redux-location-state` for new development +- **ALWAYS** use Zod schemas for URL parameter validation with fallbacks +- Use custom `QueryParamConfig` objects for encoding/decoding complex parameters +- Use `z.enum([...]).catch(defaultValue)` pattern for safe parsing with fallbacks + +```typescript +// ✅ PREFERRED pattern for URL parameters +const sortColumnSchema = z.enum(['column1', 'column2', 'column3']).catch('column1'); + +const SortOrderParam: QueryParamConfig = { + encode: (value) => (value ? encodeURIComponent(JSON.stringify(value)) : undefined), + decode: (value) => { + try { + return value ? JSON.parse(decodeURIComponent(value)) : []; + } catch { + return []; + } + }, +}; + +const [urlParam, setUrlParam] = useQueryParam('sort', SortOrderParam); +``` + ### Critical Rules - **NEVER** call APIs directly - use `window.api.module.method()` @@ -226,6 +302,8 @@ Uses React Router v5 hooks (`useHistory`, `useParams`, etc.). Always validate ro - **ALWAYS** handle loading states in UI - **ALWAYS** validate route params exist before use - **ALWAYS** follow i18n naming rules from `i18n-naming-ruleset.md` +- **ALWAYS** use Zod schemas for URL parameter validation with fallbacks +- **PREFER** `use-query-params` over `redux-location-state` for new URL parameter handling ### Debugging Tips