# Widget Architecture

> For AI: This document defines the mandatory folder structure and file organization for Dynamic Framework widgets.

---

## ⚠️ CRITICAL: Always Start with Base Template

**Before reading this document or ANY architecture documentation:**

```bash
# 1. Clone the canonical base template
git clone --depth 1 -b master https://github.com/dynamic-framework/dynamic-react-vite-base-template.git ~/Code/dynamic-2.0/generated-widgets/[widget-name]
cd ~/Code/dynamic-2.0/generated-widgets/[widget-name]
rm -rf .git
git init
npm install

# 2. Verify the copy
./VERIFY_COPY.sh
```

**If you skip this step, you WILL introduce build errors.**

Read `INDEX.md` → "Base Template First" section for complete instructions.

---

## Folder Structure

All widgets MUST follow this exact structure:

```
widget-name/
├── vite.config.ts              # Vite + Vitest Configuration
├── tsconfig.json               # TypeScript Configuration
├── package.json                # Dependencies
├── index.html                  # Entry HTML (Vite style, in root)
├── .github/                    # GitHub Configuration
│   └── workflows/             # CI/CD workflows
├── .husky/                     # Git Hooks
│   └── pre-commit             # Pre-commit hook
├── src/                        # Source Code (MAIN FOLDER)
│   ├── components/            # React Components
│   │   ├── loaders/          # Skeleton loaders
│   │   ├── modals/           # Modal components (optional)
│   │   ├── offcanvas/        # Offcanvas components (optional)
│   │   └── *.tsx             # Feature components
│   ├── config/                # Configuration Files
│   │   ├── i18nConfig.ts     # i18n setup (REQUIRED)
│   │   ├── liquidConfig.ts   # Liquid parser init (REQUIRED)
│   │   ├── liquid.json       # Liquid dev variables (REQUIRED)
│   │   └── widgetConfig.ts   # Widget constants (REQUIRED)
│   ├── hooks/                 # Custom React Hooks (UI logic)
│   │   └── *.ts              # Custom hooks
│   ├── locales/               # Translation Files
│   │   ├── en.json           # English translations (REQUIRED)
│   │   └── es.json           # Spanish translations (REQUIRED)
│   ├── services/              # Business Logic Layer
│   │   ├── api/              # API Clients
│   │   │   └── client.ts     # Axios instance (REQUIRED)
│   │   ├── hooks/            # Data Fetching Hooks
│   │   │   └── use*Effect.ts # Data fetching hooks
│   │   ├── mocks/            # Mock Data (REQUIRED)
│   │   │   └── _template.ts  # Mock data template
│   │   ├── repositories/     # Repository Pattern (REQUIRED)
│   │   │   └── _template.ts  # Repository template
│   │   ├── utils/            # Service Utilities (optional)
│   ├── store/                 # Zustand State Management
│   │   └── useUIStore.ts     # Zustand store (REQUIRED)
│   ├── providers/             # React Providers
│   │   └── QueryProvider.tsx # TanStack Query provider (REQUIRED)
│   ├── styles/                # Custom Styles
│   │   └── base.scss         # Widget styles
│   ├── utils/                 # General Utilities
│   │   ├── errorHandler.ts   # Error handling (REQUIRED)
│   │   └── liquidParser.ts   # Liquid parser (REQUIRED)
│   ├── App.tsx                # Root Component (REQUIRED)
│   ├── main.tsx               # Entry Point (REQUIRED)
│   └── vite.env.d.ts          # Vite env types
├── tests/                      # Test Files
│   └── *.test.tsx             # Test files
├── .env.example                # Environment variables template
├── eslint.config.js            # ESLint flat config (REQUIRED)
├── vite.config.ts              # Vite + Vitest configuration (REQUIRED)
├── commitlint.config.js        # Commitlint configuration
├── package.json                # Package configuration (REQUIRED)
├── tsconfig.json               # TypeScript configuration (REQUIRED)
└── README.md                   # Widget documentation
```

---

## ⚠️ CRITICAL: Documentation Files Policy

### Allowed Files

**ONLY these documentation/script files should exist in a widget:**

| File | Source | Purpose | Can Modify? |
|------|--------|---------|-------------|
| `README.md` | Base template | Widget description | ✅ Yes - update for your widget |
| `VERIFY_COPY.sh` | Base template | Template verification | ❌ No - keep as-is |

### Forbidden Files

**❌ DO NOT create these files:**

- `BUG_FIX.md`, `CHANGELOG.md`, `TROUBLESHOOTING.md`
- `QUICK_START.md` (redundant with README.md)
- `DIAGNOSTICO.md`, `ANALISIS-*.md` (process docs)
- Any other markdown file not listed above

**Why?**
- Process documentation belongs in git commits/PRs, not in code
- Quick starts belong in README.md
- Bug fixes belong in git history
- Diagnostic notes are temporary

**Where to put this information instead:**
- **README.md** - Installation, usage, features
- **Git commits** - Changes, fixes, reasoning
- **Pull requests** - Context, discussion
- **This repo's docs/** - Shared patterns, not widget-specific

### Rule for AI Agents

**If a file is not in the base template, DO NOT create it unless:**
1. User explicitly requests it by name
2. User says "create a [filename].md file"

**Exception:** User may explicitly request additional files for specific purposes.

### Validation

Validator checks for extra markdown files:
```bash
# In widget root, only these should exist:
ls *.md *.sh
# Expected: README.md VERIFY_COPY.sh
# Anything else → validator warning
```

---

## Base Template Approach

All widgets start from a pre-configured base template.

### What is Base Template?

The canonical `dynamic-react-vite-base-template` (https://github.com/dynamic-framework/dynamic-react-vite-base-template) contains a complete, pre-validated widget skeleton with:
- ✅ All configuration files (vite, TypeScript, ESLint)
- ✅ All dependencies (package.json)
- ✅ Generic utilities (errorHandler, i18n setup, liquidParser)
- ✅ index.html with Google Fonts CDN
- ✅ Empty structure ready for business logic

### Usage

**For AI:**
```bash
# Step 1: Clone the canonical base template
git clone --depth 1 -b master https://github.com/dynamic-framework/dynamic-react-vite-base-template.git ../generated-widgets/[widget-name]
cd ../generated-widgets/[widget-name]
rm -rf .git
git init
npm install

# Step 2: Generate ONLY business logic
# See INDEX.md for complete workflow
```

**For Humans:**
```bash
cd dynamic-2.0
git clone --depth 1 -b master https://github.com/dynamic-framework/dynamic-react-vite-base-template.git generated-widgets/my-new-widget
cd generated-widgets/my-new-widget
rm -rf .git
git init
npm install
```

### What's Included vs What to Generate

| Included (Copy as-is) | Generate (Widget-specific) |
|-----------------------|---------------------------|
| ✅ vite.config.ts | 📝 src/types/ |
| ✅ eslint.config.js | 📝 src/services/repositories/ |
| ✅ package.json | 📝 src/services/hooks/ |
| ✅ tsconfig.json | 📝 src/services/mocks/ |
| ✅ eslint.config.js | 📝 src/components/ |
| ✅ index.html | 📝 src/locales/en.json content |
| ✅ src/providers/QueryProvider.tsx | 📝 src/locales/es.json content |
| ✅ src/store/useUIStore.ts (structure) | 📝 Update useUIStore.ts with widget state |
| ✅ src/utils/errorHandler.ts | 📝 src/config/widgetConfig.ts (update name) |
| ✅ src/config/i18nConfig.ts (structure) | 📝 i18nConfig.ts resources |

### Why Base Template?

**Before (generating everything):**
- ~40 files to generate
- ~12,000 tokens
- 3-5 iterations
- Common config errors

**After (using base template):**
- ~12 files to generate
- ~4,000 tokens
- 1-2 iterations
- Zero config errors

### Template Maintenance

When updating the base template:
1. Edit it in the canonical repo `dynamic-framework/dynamic-react-vite-base-template` and open a PR there.
2. Future widgets inherit changes once the compatibility matrix is bumped: the `widgets-scaffold` Tool always clones the tag pinned in `WIDGETS_COMPAT.template`, never `master` — tag a release in the canonical repo and bump the matrix in the MCP.
3. Existing widgets can update by copying specific files.

**See:** https://github.com/dynamic-framework/dynamic-react-vite-base-template#readme for complete template documentation.

---

## Required Folders

These folders MUST exist in every widget:

| Folder | Purpose | Can be Empty? |
|--------|---------|---------------|
| `src/components/` | React UI components | ❌ NO |
| `src/components/loaders/` | Skeleton loaders | ✅ YES |
| `src/config/` | Configuration files | ❌ NO |
| `src/hooks/` | Custom React hooks | ✅ YES |
| `src/locales/` | i18n translation files | ❌ NO |
| `src/services/api/` | API clients (Axios) | ❌ NO |
| `src/services/mocks/` | Mock data | ❌ NO |
| `src/services/hooks/` | Data fetching hooks | ✅ YES |
| `src/services/repositories/` | Repository pattern | ❌ NO |
| `src/store/` | Zustand state | ❌ NO |
| `src/styles/` | Custom SCSS | ✅ YES |
| `src/types/` | TypeScript types | ❌ NO |
| `src/utils/` | Utility functions | ❌ NO |
| `tests/` | Test files | ❌ NO |

---

## Required Files

These files MUST exist in every widget:

### Configuration Files
- `package.json` - Package configuration
- `tsconfig.json` - TypeScript configuration (strict mode)
- `vite.config.ts` - Vite + Vitest configuration
- `eslint.config.js` - ESLint flat config (ESLint 9)
- `index.html` - Entry HTML (at project root, Vite standard)

---

### index.html Template

**CRITICAL**: The entry HTML file lives at the **project root** (not in `public/`). This is Vite's standard.

```html
<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />

  <!-- Jost Typography (Google Fonts CDN) -->
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Jost:wght@400;500;600&display=swap" rel="stylesheet">

  <title>Widget Title</title>
</head>
<body>
  <div id="widgetName" class="widget-name"></div>
  <script type="module" src="/src/main.tsx"></script>
</body>
</html>
```

**Critical Elements**:

1. **Jost Typography**: Official Dynamic Framework typography via Google Fonts CDN
2. **Icons**: Lucide React icons are included via `@dynamic-framework/ui-react` — no external CDN needed
3. **CSS**: Dynamic UI CSS is imported in `src/main.tsx` via `import '@dynamic-framework/ui-react/dist/css/dynamic-ui.css'`

**Don't**:
- ❌ Don't add Bootstrap Icons CDN (Lucide is bundled with the library)
- ❌ Don't put `index.html` in `public/` (Vite serves it from root)

---

### Source Files
- `src/main.tsx` - Entry point
- `src/App.tsx` - Root component
- `src/config/i18nConfig.ts` - i18n setup (uses `configureI18n`)
- `src/config/liquidConfig.ts` - Liquid parser setup
- `src/config/liquid.json` - Liquid development variables
- `src/config/widgetConfig.ts` - Widget constants (parsed from Liquid)
- `src/locales/en.json` - English translations
- `src/locales/es.json` - Spanish translations
- `src/services/api/client.ts` - Axios instance
- `src/services/mocks/_template.ts` - Mock data template
- `src/services/repositories/_template.ts` - Repository template
- `src/store/useUIStore.ts` - Zustand store
- `src/providers/QueryProvider.tsx` - TanStack Query provider
- `src/types/index.ts` - Shared TypeScript types
- `src/utils/errorHandler.ts` - Error handler
- `src/utils/liquidParser.ts` - Liquid parser utility
- `src/vite.env.d.ts` - Vite environment type declarations

### Test Files
- `tests/` folder with `*.test.tsx` files

---

## Naming Conventions

### Files and Folders

| Type | Pattern | Example | Anti-pattern |
|------|---------|---------|--------------|
| Component Files | `PascalCase.tsx` | `AccountCard.tsx` | `account-card.tsx` |
| Hook Files | `camelCase.ts` | `useAccountValue.ts` | `UseAccountValue.ts` |
| Util Files | `camelCase.ts` | `errorHandler.ts` | `ErrorHandler.ts` |
| Repository Files | `PascalCaseRepository.ts` | `AccountRepository.ts` | `account-repository.ts` |
| Mapper Files | `camelCaseMapper.ts` | `accountMapper.ts` | `AccountMapper.ts` |
| Service Hook Files | `use[Entity]Effect.ts` | `useAccountsEffect.ts` | `getAccounts.ts` |
| Test Files | `*.spec.tsx` or `*.test.tsx` | `App.spec.tsx` | `App.test.js` |
| Style Files | `camelCase.scss` | `base.scss` | `Base.scss` |

### Code Elements

| Element | Convention | Example | Anti-pattern |
|---------|-----------|---------|--------------|
| Components | `PascalCase` | `AccountCard` | `accountCard` |
| Hooks | `use[Purpose]` | `useAccountValue` | `getAccountValue` |
| Data Hooks | `use[Entity]Effect` | `useAccountsEffect` | `fetchAccounts` |
| Repositories | `[Entity]Repository` | `AccountRepository` | `AccountService` |
| Mappers | `[entity]Mapper` | `accountMapper` | `AccountMapper` |
| Utils | `camelCase` | `errorHandler` | `ErrorHandler` |
| Constants | `SCREAMING_SNAKE_CASE` | `API_BASE_URL` | `ApiBaseUrl` |
| Types/Interfaces | `PascalCase` | `Account`, `ApiAccount` | `account` |
| Zustand Actions | `set[Property]` | `setAccounts` | `updateAccounts` |
| Selectors | `get[Property]` | `getAccounts` | `selectAccounts` |

---

## Folder Organization Best Practices

### Components Folder (`src/components/`)

Organize components by feature or type:

```
components/
├── loaders/                   # Skeleton loaders
│   ├── AccountCardLoader.tsx
│   └── ListLoader.tsx
├── modals/                    # Modal dialogs
│   ├── ModalActivate.tsx
│   └── ModalConfirm.tsx
├── offcanvas/                 # Offcanvas panels
│   └── OffcanvasFilters.tsx
├── AccountCard.tsx            # Feature components
├── TransactionList.tsx
└── QuickTransfer.tsx
```

**Rules:**
- One component per file
- Component name = File name
- Group related components in subfolders
- Loaders should mirror the component they load (e.g., `AccountCardLoader` for `AccountCard`)

---

### Services Folder (`src/services/`)

Strict separation of concerns:

```
services/
├── api/
│   └── client.ts              # Axios instance configuration
├── hooks/
│   ├── useAccountsEffect.ts   # Fetch accounts
│   └── useActivitiesEffect.ts # Fetch activities
├── mocks/
│   └── accounts.ts            # Mock data for development
├── repositories/
│   ├── AccountRepository.ts   # Account CRUD operations
│   └── ActivityRepository.ts
└── utils/                     # Service-specific utilities (optional)
```

**Rules:**
- Repositories handle API calls
- Hooks orchestrate fetching and state updates
- Mock data toggled via `USE_MOCKS` from `widgetConfig.ts`
- Clear separation: repositories → hooks → components

---

### Store Folder (`src/store/`)

Zustand store structure (1 file):

```
store/
└── useUIStore.ts              # Zustand store for UI state
```

**Rules:**
- One store per widget
- UI state only (filters, selections, modals)
- Server data via TanStack Query hooks
- Use selectors for optimal re-renders: `useUIStore((state) => state.field)`

**What belongs in Zustand:**
- Filter selections, modal open/close, active tab/step, form field values (before submission), UI preferences

**What does NOT belong in Zustand:**
- Server data (use TanStack Query), cached API responses (use TanStack Query)

---

### Config Folder (`src/config/`)

Configuration files:

```
config/
├── i18nConfig.ts              # i18n setup
├── liquidConfig.ts            # Liquid parser initialization
├── liquid.json                # Development Liquid variables
└── widgetConfig.ts            # Widget constants (parsed from Liquid)
```

**Rules:**
- All Liquid template parsing in `widgetConfig.ts`
- i18n configuration separate from translations
- Development variables in `liquid.json`

---

## File Dependencies Flow

Understanding the dependency flow is critical:

```
main.tsx
  └─> App.tsx
       ├─> DContextProvider (Dynamic UI)
       ├─> QueryClientProvider (TanStack Query)
       └─> Components
            ├─> Custom Hooks (from /hooks)
            ├─> TanStack Query Hooks (from /services/hooks)
            │    └─> Repositories (from /services/repositories)
            │         └─> API Client (from /services/api/client)
            ├─> Zustand Store (from /store/useUIStore)
            └─> Dynamic UI Components
```

**Key Rules:**
- Components should NOT import repositories directly
- Use TanStack Query hooks for server data
- Zustand for UI state (filters, modals, selections)

---

## Optional Folders

These folders are optional and used based on widget needs:

| Folder | Purpose | When to Use |
|--------|---------|-------------|
| `src/components/modals/` | Modal components | Widget has modal dialogs |
| `src/components/offcanvas/` | Offcanvas panels | Widget has slide-in panels |
| `src/services/utils/` | Service-specific utilities | Complex service logic |
| `.github/workflows/` | CI/CD pipelines | Automated testing/deployment |

---

## Widget Size Guidelines

### Small Widget (< 500 LOC)
- 1-3 components
- 1 repository
- 1 data hook
- Minimal custom hooks

### Medium Widget (500-1500 LOC)
- 4-8 components
- 2-3 repositories
- 2-4 data hooks
- 1-3 custom hooks
- May have modals or offcanvas

### Large Widget (> 1500 LOC)
- 9+ components
- 3+ repositories
- 4+ data hooks
- Multiple custom hooks
- Modals and/or offcanvas
- Complex state management

---

## Common Mistakes to Avoid

❌ **Don't:**
- Mix business logic in components
- Import repositories directly in components
- Create wrappers for Dynamic UI components
- Use default exports (use named exports)
- Nest components more than 2 levels deep
- Skip error handling in repositories
- Forget AbortController in data hooks

✅ **Do:**
- Follow the folder structure exactly
- Use Zustand selectors for optimal re-renders
- Handle errors with errorHandler utility
- Use AbortSignal for request cancellation
- Keep components focused on rendering
- Use proper naming conventions
- Document complex logic with comments

---

## Legacy Files (Do NOT Create)

These patterns are from the old Webpack + Redux stack:

| Do NOT Create | Reason |
|---------------|--------|
| `.config/` folder | Was Webpack plugins, Vite doesn't need |
| `babel.config.js` | Vite uses esbuild |
| `jest.config.js` | ❌ Legacy — Using Vitest |
| `src/index.tsx` | ❌ Legacy — Use `src/main.tsx` with Vite |
| `src/store/index.ts` | Was Redux store |
| `src/store/hooks.ts` | Was Redux typed hooks |
| `src/store/*Slice.ts` | Was Redux slices |
| `src/store/selectors.ts` | Was Redux selectors |
| `webpack.config.js` | ❌ Legacy — Using Vite |

---

## Consistency Checklist

Before finalizing a widget, verify:

- [ ] All required folders exist
- [ ] All required files are present
- [ ] File naming follows conventions
- [ ] Folder structure matches template
- [ ] No mixing of concerns (UI vs business logic)
- [ ] TypeScript strict mode enabled
- [ ] ESLint and Stylelint configured
- [ ] Tests setup file exists
- [ ] i18n configured with en.json and es.json
- [ ] Zustand store and TanStack Query properly configured

---

**End of Architecture Document**
