# Widget Validator Rules

> For AI: Rules that all widgets must satisfy. Target score: >= 95%

---

## Validation Categories

Validations are grouped into categories. Each category has specific rules that are checked.

### Category Summary

<!-- TODO: Review validator categories - table shows 13 categories (71 rules) but validator reports 20 categories (98 checks). Missing: UI Patterns, Project Structure, Data States, Error Boundary, Accessibility, and others from rules/*.ts -->

| Category | Priority | Rules | Severity |
|----------|----------|-------|----------|
| Folder Structure | CRITICAL | 12 | ERROR |
| Required Files | CRITICAL | 12 | ERROR |
| Naming Conventions | HIGH | 8 | ERROR |
| Dependencies | HIGH | 8 | WARNING |
| TypeScript Config | MEDIUM | 5 | ERROR |
| i18n | MEDIUM | 4 | ERROR |
| Testing (Vitest) | MEDIUM | 3 | WARNING |
| Vite Configuration | CRITICAL | 3 | ERROR |
| TanStack Query | HIGH | 3 | ERROR |
| Zustand Store | HIGH | 3 | ERROR |
| Error Handling | LOW | 2 | ERROR/WARNING |
| Repository Pattern | MEDIUM | 4 | ERROR/WARNING |
| Portal System | HIGH | 4 | ERROR/WARNING |

---

## 1. Folder Structure (CRITICAL)

All required folders must exist.

### Required Folders

| Folder Path | Purpose | Severity |
|-------------|---------|----------|
| `public/` | Static assets (favicon, etc.) | ERROR |
| `src/components/` | React components | ERROR |
| `src/components/loaders/` | Skeleton loaders | ERROR |
| `src/config/` | Configuration files | ERROR |
| `src/hooks/` | Custom React hooks | ERROR |
| `src/locales/` | Translation files | ERROR |
| `src/providers/` | React context providers | ERROR |
| `src/services/` | Business logic | ERROR |
| `src/services/api/` | API clients (Axios) | ERROR |
| `src/services/mocks/` | Mock data for development | ERROR |
| `src/services/repositories/` | Repository pattern | ERROR |
| `src/store/` | Zustand UI state | ERROR |
| `src/styles/` | Custom SCSS | WARNING |
| `src/types/` | TypeScript type definitions | ERROR |
| `src/utils/` | Utility functions | ERROR |
| `tests/` | Test files | ERROR |


---

## 2. Required Files (CRITICAL)

Core files that must exist in every widget.

### Root Level Configuration

| File | Purpose | Severity |
|------|---------|----------|
| `package.json` | Package configuration | ERROR |
| `vite.config.ts` | Vite build configuration | ERROR |
| `tsconfig.json` | TypeScript config | ERROR |
| `index.html` | Entry HTML (Vite serves from root) | ERROR |
| `eslint.config.js` | ESLint flat config | ERROR |

### Source Files

| File | Purpose | Severity |
|------|---------|----------|
| `src/main.tsx` | Application entry point | ERROR |
| `src/App.tsx` | Root component | ERROR |
| `src/providers/QueryProvider.tsx` | TanStack Query setup | ERROR |
| `src/store/useUIStore.ts` | Zustand UI state | ERROR |
| `src/config/i18nConfig.ts` | i18n setup | ERROR |
| `src/config/widgetConfig.ts` | Widget constants | ERROR |
| `src/locales/en/translation.json` | English translations | ERROR |
| `src/locales/es/translation.json` | Spanish translations | ERROR |
| `src/services/api/client.ts` | Axios instance | ERROR |
| `src/services/repositories/_queryTemplate.ts` | Query hook template | WARNING |
| `src/types/index.ts` | Shared TypeScript types | ERROR |
| `src/utils/errorHandler.ts` | Error handler | ERROR |

### Removed (Legacy - Should NOT Exist)

These files are from the old stack and should NOT exist:

| File | Reason |
|------|--------|
| ~~`.config/`~~ | Webpack plugins folder - Vite doesn't need this |
| ~~`babel.config.js`~~ | Vite uses esbuild for transpilation |
| ~~`jest.config.js`~~ | ❌ Legacy — Using Vitest (configured in vite.config.ts) |
| ~~`src/store/store.ts`~~ | Was Redux store - using Zustand |
| ~~`src/store/hooks.ts`~~ | Was Redux typed hooks - not needed |
| ~~`src/store/*Slice.ts`~~ | Was Redux slices - using Zustand |
| ~~`public/index.html`~~ | Vite uses index.html at root |


---

## 3. Naming Conventions (HIGH)

Files and code elements must follow naming patterns.

### File Naming

| Type | Pattern | Example | Anti-pattern |
|------|---------|---------|--------------|
| Component | `PascalCase.tsx` | `AccountCard.tsx` | `account-card.tsx` |
| Hook | `camelCase.ts` | `useAccountValue.ts` | `UseAccountValue.ts` |
| Repository | `PascalCaseRepository.ts` | `AccountRepository.ts` | `account-repository.ts` |
| Mapper | `camelCaseMapper.ts` | `accountMapper.ts` | `AccountMapper.ts` |
| Service Hook | `use[Entity]Effect.ts` | `useAccountsEffect.ts` | `fetchAccounts.ts` |


---

## 4. Dependencies (HIGH)

Verify correct versions of core dependencies.

### Required Dependencies

| Package | Min Version | Purpose |
|---------|-------------|---------|
| `react` | 19.0.0 | React library |
| `react-dom` | 19.0.0 | React DOM |
| `@dynamic-framework/ui-react` | 2.0.0 | Dynamic UI components |
| `@tanstack/react-query` | 5.0.0 | Server state management |
| `zustand` | 5.0.0 | UI state management |
| `axios` | 1.0.0 | HTTP client |
| `i18next` | 25.0.0 | i18n core |
| `react-i18next` | 16.0.0 | React i18n |
| `framer-motion` | 12.0.0 | Animations |

### Required DevDependencies

| Package | Min Version | Purpose |
|---------|-------------|---------|
| `typescript` | 5.0.0 | TypeScript |
| `vite` | 6.0.0 | Build tool |
| `@vitejs/plugin-react` | 4.0.0 | Vite React plugin |
| `vitest` | 2.0.0 | Testing |
| `@testing-library/react` | 16.0.0 | React testing |
| `eslint` | 9.0.0 | Linting |
| `@tanstack/react-query-devtools` | 5.0.0 | Query debugging |

### Forbidden Dependencies (Legacy)

These should NOT be in package.json:

| Package | Reason |
|---------|--------|
| ~~`@reduxjs/toolkit`~~ | Using Zustand instead |
| ~~`react-redux`~~ | Using Zustand instead |
| ~~`webpack`~~ | Using Vite instead |
| ~~`babel-*`~~ | Vite uses esbuild |
| ~~`jest`~~ | Using Vitest instead |


---

## 5. TypeScript Configuration (MEDIUM)

Verify TypeScript is configured correctly.

### Required Settings

| Setting | Required Value | Purpose |
|---------|----------------|---------|
| `strict` | `true` | Enable all strict checks |
| `target` | `es2017` or higher | Target ES version |
| `module` | `esnext` | Module system |
| `jsx` | `react-jsx` | JSX transform |
| `moduleResolution` | `node` | Module resolution |
| `esModuleInterop` | `true` | ES module interop |


---

## 6. i18n (MEDIUM)

Verify internationalization is properly configured.

### Rules

| Rule | Description | Severity |
|------|-------------|----------|
| `en.json` exists | English translations file | ERROR |
| `es.json` exists | Spanish translations file | ERROR |
| `en.json` not empty | Has at least 1 translation | ERROR |
| `es.json` not empty | Has at least 1 translation | ERROR |


---

## 7. Testing with Vitest (MEDIUM)

Verify Vitest testing infrastructure is in place.

### Rules

| Rule | Description | Severity |
|------|-------------|----------|
| `tests/` folder exists | Test folder present | ERROR |
| Vitest configured | In vite.config.ts or vitest.config.ts | ERROR |
| At least 1 test file | At least 1 `.test.tsx` file | WARNING |


---

## 8. Vite Configuration (CRITICAL)

Verify Vite is configured correctly.

### Rules

| Rule | Description | Severity |
|------|-------------|----------|
| `vite.config.ts` exists | Vite config file | ERROR |
| `@vitejs/plugin-react` used | React plugin configured | ERROR |
| Environment variables use `VITE_` prefix | Not `REACT_APP_` | WARNING |


**Correct Setup:**

```typescript
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  server: { port: 3000 },
  test: {
    globals: true,
    environment: 'jsdom',
  },
});
```

**Environment Variables:**

```typescript
// ❌ OLD (Webpack)
const apiUrl = process.env.REACT_APP_API_URL;

// ✅ NEW (Vite)
const apiUrl = import.meta.env.VITE_API_URL;
```

---

## 9. Error Handling (LOW)

Verify error handling utilities exist.

### Rules

| Rule | Description | Severity |
|------|-------------|----------|
| `errorHandler.ts` exists | Error handler utility | ERROR |
| `errorHandler` is default export | Proper export | WARNING |


---

## 10. Repository Pattern (MEDIUM)

Verify repository pattern is implemented.

### Rules

| Rule | Description | Severity |
|------|-------------|----------|
| `repository.ts` exists | Base types file | ERROR |
| At least 1 `*Repository.ts` file | Repository implementation | ERROR |
| Repositories export async functions | Named exports, async | WARNING |
| Repository uses AbortSignal | Proper cancellation support | WARNING |


---

## 11. TanStack Query Setup (HIGH)

Verify TanStack Query is configured for server state management.

### Rules

| Rule | Description | Severity |
|------|-------------|----------|
| `QueryProvider.tsx` exists | Provider component | ERROR |
| `QueryClient` configured | Client with defaults | ERROR |
| No Redux for server data | Server data uses useQuery | WARNING |


**Correct Setup:**

> See `modyo://docs/widgets/patterns-tanstack-query` for complete QueryProvider setup.

---

## 12. Zustand Store (HIGH)

Verify Zustand is configured for UI state management.

### Rules

| Rule | Description | Severity |
|------|-------------|----------|
| `useUIStore.ts` exists | Store file | ERROR |
| Uses `create` from zustand | Proper store setup | ERROR |
| No server data in store | Only UI state | WARNING |


**Correct Setup:**

> See `modyo://docs/widgets/patterns-zustand` for complete store setup.

**State Separation:**

| Data Type | Solution | Example |
|-----------|----------|---------|
| API data | TanStack Query | `useQuery(['accounts'], getAccounts)` |
| Selections | Zustand | `useUIStore(s => s.selectedId)` |
| Form values | React state | `useState()` |
| URL state | Router | URL params |

---

## 13. Portal System (HIGH)

Verify modals and offcanvas are properly registered in DContextProvider.

### Rules

| Rule | Description | Severity |
|------|-------------|----------|
| `availablePortals` in main.tsx | Portal registration prop present | WARNING |
| Modals detected require `availablePortals` | If modals exist, must be registered | ERROR |
| Modal components imported | Modal imports in main.tsx | WARNING |
| Portal names match | DModal `name` matches `availablePortals` key | ERROR |


**Why This Is Critical:**

Without registering modals in `availablePortals`, opening them will cause runtime errors:
```
ERROR: there is no component for portal modal-name
```

**Correct Setup:**

```tsx
// src/main.tsx
import { DContextProvider } from '@dynamic-framework/ui-react';
import ConfirmModal from './components/modals/ConfirmModal';
import DetailsModal from './components/modals/DetailsModal';

root.render(
  <DContextProvider
    availablePortals={{
      'confirm-modal': ConfirmModal,
      'details-modal': DetailsModal,
    }}
  >
    <App />
  </DContextProvider>
);
```

```tsx
// src/components/modals/ConfirmModal.tsx
export default function ConfirmModal() {
  return (
    <DModal name="confirm-modal"> {/* name must match availablePortals key */}
      {/* modal content */}
    </DModal>
  );
}
```

---

## Scoring System

### Score Calculation

```
Score = (Passed Checks / Total Checks) × 100
```

### Severity Impact

- **ERROR**: Check must pass
- **WARNING**: Check should pass but not critical

### Pass Threshold

- **95%+**: Widget passes validation ✅
- **85-94%**: Widget passes with warnings ⚠️
- **<85%**: Widget fails validation ❌

### Example Report

```
Widget: dynamic-retail-dashboard-template
Score: 97% ✅

Checks: 58/60 passed

✅ PASSED:
- All required folders exist (12/12)
- All required files exist (15/15)
- Naming conventions correct (8/8)
- Dependencies installed (10/10)
- TypeScript configured (5/5)
- i18n setup (4/4)

⚠️ WARNINGS:
- Only 3 test files (expected 5+)
- One repository missing AbortSignal support

❌ ERRORS:
None
```

---

## Validation Priority

When generating widgets, validate in this order:

1. **Folder Structure** - Foundation must be correct
2. **Required Files** - Core files must exist
3. **Vite Config** - Build tool configured correctly
4. **TypeScript Config** - Type safety must be enabled
5. **Dependencies** - Correct packages (TanStack Query, Zustand, NO Redux)
6. **TanStack Query** - QueryProvider configured
7. **Zustand Store** - UI state only
8. **i18n** - Translations must exist
9. **Naming Conventions** - Follow patterns
10. **Repository Pattern** - Data access correct
11. **Portal System** - Modals/offcanvas registered if present
12. **Testing (Vitest)** - Tests present
13. **Error Handling** - Error utilities exist

---

## Quick Validation Checklist

For AI: Before marking a widget as complete, verify:

### Build & Config
- [ ] `vite.config.ts` exists with React plugin
- [ ] `index.html` at root (NOT in public/)
- [ ] `tsconfig.json` with strict mode enabled
- [ ] `eslint.config.js` exists (flat config)
- [ ] NO `.config/` folder (Webpack legacy)
- [ ] NO `babel.config.js` (Vite uses esbuild)

### Dependencies
- [ ] `@tanstack/react-query` >= 5.0.0
- [ ] `zustand` >= 5.0.0
- [ ] `@dynamic-framework/ui-react` >= 2.0.0
- [ ] NO `@reduxjs/toolkit` or `react-redux`
- [ ] NO `webpack` or `jest`

### State Management
- [ ] `src/providers/QueryProvider.tsx` exists with QueryClient
- [ ] `src/store/useUIStore.ts` exists with Zustand create()
- [ ] ❌ NO Redux patterns (useAppDispatch, createSlice)
- [ ] Server data in TanStack Query, UI state in Zustand

### Structure
- [ ] All required folders exist (see §1)
- [ ] `src/main.tsx` entry point exists
- [ ] `src/services/api/client.ts` exists
- [ ] `src/services/repositories/` has at least one repository
- [ ] `src/types/index.ts` exists

### i18n
- [ ] `src/locales/en/translation.json` exists and not empty
- [ ] `src/locales/es/translation.json` exists and not empty

### Portal System
- [ ] If modals exist, they are registered in `availablePortals`
- [ ] Modal `name` prop matches `availablePortals` key

### Testing
- [ ] `tests/` folder exists
- [ ] At least 1 test file exists
- [ ] Vitest configured (in vite.config.ts or vitest.config.ts)

### Naming
- [ ] Component files are PascalCase.tsx
- [ ] Repository files are PascalCaseRepository.ts
- [ ] Score >= 95%

---

## Production Ready Rules (Fases 1-4)

Estas reglas garantizan que los widgets cumplan el estándar de production ready.

### Data States (Fase 1)

| Rule ID | Severity | Description |
|---------|----------|-------------|
| `data-states/loading-handled` | error | Components must check isLoading |
| `data-states/error-handled` | error | Components must check isError |
| `data-states/empty-handled` | warning | Lists must handle empty state |

### Error Boundaries (Fase 2)

| Rule ID | Severity | Description |
|---------|----------|-------------|
| `error-boundary/component-exists` | error | ErrorBoundary.tsx must exist |
| `error-boundary/used-in-app` | error | App.tsx must use ErrorBoundary |

### Testing (Fase 3)

| Rule ID | Severity | Description |
|---------|----------|-------------|
| `testing/min-test-files` | error | At least 1 test file required |
| `testing/hooks-have-tests` | warning | Hooks should have test files |
| `testing/tests-folder-structure` | warning | Tests in __tests__ folders |

### Accessibility (Fase 4)

| Rule ID | Severity | Description |
|---------|----------|-------------|
| `a11y/inputs-have-labels` | warning | DInput needs label/aria-label |
| `a11y/buttons-have-text` | warning | DButton needs text/aria-label |
| `a11y/images-have-alt` | warning | img tags need alt attribute |

**Total nuevas reglas:** 11

---

**End of Validator Rules Document**
