---
description: Foundational invariants for dashboard modules. Defines what is allowed and forbidden, and why. Read this to understand the principles before working on any module.
paths:
  - "src/pages/dashboard/**"
---

# Module Architecture — Invariants

Rules that never change. Everything else in the architecture derives from these principles.
For the structural reference (directory tree, naming, checklist), see `module-architecture.md`.

---

## Principles

### 1. Module as isolated container

Each module is self-contained. Copy the folder to another project and it should work
with minimal external dependencies (the "copy-paste test").

**Allowed external dependencies:**

- `src/components/` — shared global components (UI kit, guards, layout)
- `src/contexts/` — global contexts (auth, feature flags, socket, settings)
- `src/config/` — global configuration (react-query client, API base, i18n)
- `src/utils/` — truly generic utilities (arrays, date, i18n, permissions)
- `src/types/` — only base types shared across multiple modules (User, Instance, Pagination)
- `src/hooks/` — only truly global hooks (useQuery wrapper, useFeatureFlag, usePermissions)
- External libraries (react, react-router, react-query, zod, mui, etc.)

Everything else lives inside the module folder.

### 2. No barrel exports

Do not create `index.ts` barrel files (files that only re-export from other files).
Barrels provide little value and break tree-shaking given how the codebase is structured.

```typescript
// ✅ Import directly from the file
import { getGoals } from 'src/pages/dashboard/Goals/services';
import type { Goal } from 'src/pages/dashboard/Goals/types';

// ❌ No barrels
import { getGoals } from 'src/pages/dashboard/Goals';
```

This also applies to split folders: no `types/index.ts`, no `services/index.ts`, no `hooks/index.ts`.

### 3. No cross-module imports

Do NOT import from another module (`src/pages/dashboard/OtherModule/`).
If two modules share logic, promote it to `src/components/`, `src/hooks/`, or `src/utils/`.

### 4. index.tsx = real component

Every `index.tsx` is an actual React component — the entry point of the module or page.
Never use `index.ts` (no JSX) as a barrel re-exporter.

---

## Dependency rules

Direct consequence of the principles above:

```
ALLOWED:
  module/* → src/components/*     (shared UI)
  module/* → src/contexts/*       (global contexts)
  module/* → src/config/*         (global config)
  module/* → src/utils/*          (generic utils)
  module/* → src/types/*          (shared base types)
  module/* → src/hooks/*          (global hooks)
  module/* → node_modules         (external libraries)
  module/PageA/* → module/*       (page imports from module root)
  module/PageA/* → module/components/*  (page uses shared module components)

FORBIDDEN:
  module/* → src/pages/dashboard/OtherModule/*   (NO cross-module imports)
  module/* → src/services/*       (service must live inside the module)
  module/* → src/constants/*      (module constants must be local)
  module/PageA/* → module/PageB/* (NO cross-page imports within the module)
```

If `PageA` and `PageB` need to share something, promote it to the module root
(`components/`, `hooks/`, `utils.ts`, etc.).

---

## File splitting

Aim for files no longer than ~300 lines. Add section comments
(`// --- Queries ---`, `// --- Mutations ---`) for quick navigation.

Split by semantic domain, not by line count:

- `services.ts` → `services/domain.ts` — import directly, no barrel
- `types.ts` → `types/entities.ts`, `types/api.ts` — no barrel
- `utils.ts` → `utils/responsibility.ts` — no barrel
- Large components (400+ lines) → extract subcomponents into `components/`

After any split or refactor, run `biome check` to verify imports.

---

## Existing code

**Do NOT** proactively refactor or migrate existing modules to match this architecture.
Apply these conventions only when:

- Creating a new module from scratch
- Explicitly asked to migrate or refactor

If existing code doesn't follow these rules, leave it as-is.

To migrate an existing module, use the `/migrate-module {ModuleName}` command.
**Do not migrate unless the user explicitly requests it.**
Migrate module by module, one PR per module.
