TorbatYar/frontend/docs/module-boundaries.md
Mortezakoohjani 6f4a484051 Migrate Beauty, Healthcare, and Accounting frontend to modular src/modules architecture.
Move business logic out of App Router into module packages, add boundary validation scripts, and keep all routes as thin re-exports without changing URLs or API behavior.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-26 22:28:27 +03:30

289 lines
9.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# TorbatYar Frontend — Module Boundaries
**Date:** 2026-07-26
**Scope:** Frontend import and ownership rules
**Aligns with:** `docs/architecture/module-boundaries.md` (platform-level)
---
## 1. Module Inventory
| Module ID | Route prefix | Component root | API client | BFF route |
|-----------|--------------|----------------|------------|-----------|
| **platform** | `/`, `/login`, `/register`, `/onboarding`, `/dashboard`, `/auth` | `components/` (root), `components/ui/`, `components/auth/` | `lib/api.ts`, `lib/auth.ts`, `lib/identity.ts` | None (direct) |
| **admin** | `/admin` | `components/admin/` | `lib/api.ts` | None (direct) |
| **accounting** | `/accounting` | `src/modules/accounting/` | `src/modules/accounting/services/accounting-api.ts` | `/api/accounting/*` |
| **beauty** | `/beauty` | `modules/beauty/` | `modules/beauty/services/beauty-business-api.ts` | `/api/beauty-business/*` |
| **healthcare** | `/healthcare` | `src/modules/healthcare/` | `src/modules/healthcare/services/healthcare-api.ts` | `/api/healthcare/*` |
**Not yet in frontend:** delivery (backend exists; UI only via healthcare pharmacy portal), loyalty, communication, sports center, experience.
**Partially migrated:** CRM (`modules/crm/`), Hospitality (`modules/hospitality/`).
---
## 2. Shared Layer (Cross-Module)
These folders are **owned by the platform** and may be imported by any module:
```
components/ds/ # Design system — MUST remain domain-agnostic
components/providers/ # Query, color mode
components/AuthGuard.tsx
components/AdminAuthGuard.tsx
components/ThemeProvider.tsx
components/SiteHeader.tsx
components/TenantSwitcher.tsx
components/RouteProgress.tsx
components/AppStoreGrid.tsx
components/settings/ # Account settings (platform)
hooks/ # All shared hooks
lib/utils.ts
lib/auth.ts
lib/theme.ts
lib/apps-catalog.ts
styles/globals.css
```
### Shared layer rules
| Rule | Status |
|------|--------|
| `components/ds/` MUST NOT import from domain modules | ✅ Compliant |
| Shared hooks MUST NOT import domain API clients | ✅ Compliant |
| Shared hooks MAY import `lib/auth.ts`, `lib/api.ts` (platform) | ✅ By design |
| Platform components MUST NOT import domain shells | ✅ Compliant |
---
## 3. Domain Layer Rules
Each business module owns:
```
app/{module}/ # Routes and layouts (thin re-exports when migrated)
src/modules/{module}/ # Healthcare, Accounting module root
modules/{module}/ # Beauty, CRM, Hospitality module root
components/{module}/ # Legacy (removed for migrated modules)
lib/{module}-api.ts # Deprecated shims → module services
hooks/use{Module}*.ts # Deprecated shims → module hooks
app/api/{service}/ # BFF proxy
```
### Allowed import directions
```
┌─────────────┐
│ shared │
│ ds, hooks │
│ lib/auth │
└──────▲──────┘
┌─────────────────┼─────────────────┐
│ │ │
┌─────┴─────┐ ┌──────┴──────┐ ┌──────┴──────┐
│ accounting │ │ beauty │ │ healthcare │
└───────────┘ └─────────────┘ └─────────────┘
✕ ✕ ✕
└──────────────── no cross-imports ──┘
```
| From → To | platform/shared | accounting | beauty | healthcare | admin |
|-----------|:-:|:-:|:-:|:-:|:-:|
| **platform** | ✅ | ❌ | ❌ | ❌ | ✅ (shell only) |
| **accounting** | ✅ | ✅ | ❌ | ❌ | ❌ |
| **beauty** | ✅ | ❌ | ✅ | ❌ | ❌ |
| **healthcare** | ✅ | ❌ | ❌ | ✅ | ❌ |
| **admin** | ✅ | ❌ | ❌ | ❌ | ✅ |
| **ds** | ✅ (internal) | ❌ | ❌ | ❌ | ❌ |
**Current compliance:** ✅ Zero cross-domain imports detected.
---
## 4. Route Layer Rules
### What routes MAY contain
- `"use client"` directive
- Default export (page component or re-export)
- Metadata exports (server components only)
- Dynamic route param typing
- Thin re-exports to `components/{module}/`
### What routes MUST NOT contain
- Direct `fetch()` to microservice origins (use BFF or lib API client)
- Business validation logic (>20 lines)
- Form schemas (belong in components or `lib/schemas/`)
- Reusable UI subcomponents (belong in `components/{module}/`)
- Cross-module imports
### Current compliance by module
| Module | Route thinness | Compliance |
|--------|----------------|------------|
| Beauty (portals/site) | 23 line re-exports | ✅ Excellent |
| Healthcare (portals/site) | 23 line re-exports | ✅ Excellent |
| Beauty `(owner)` CRUD | 44245 lines inline | ⚠️ Violation |
| Accounting | 3663 lines inline | ❌ Major violation |
| Platform/admin | Mixed | ⚠️ Acceptable |
---
## 5. API Boundary Rules
### Client-side API access
| API | Access method | Correct |
|-----|---------------|---------|
| Accounting service | `accountingApi.*``/api/accounting/*` | ✅ |
| Beauty business service | `beautyBusinessApi.*``/api/beauty-business/*` | ✅ |
| Healthcare service | `healthcareApi.*``/api/healthcare/*` | ✅ |
| Core platform | `api.*``NEXT_PUBLIC_BACKEND_URL` | ✅ |
| Identity/Keycloak | `identity.*``NEXT_PUBLIC_IDENTITY_API_URL` | ✅ |
### Forbidden
- Importing another module's API client
- Calling microservice ports directly from browser (bypassing BFF)
- Storing business rules in BFF route handlers (proxies must stay thin)
---
## 6. State & Cache Boundaries
### Query key namespaces
Each module owns its query key prefix:
```typescript
// Platform
["me"]
["theme", tenantId]
// Accounting
["accounting", tenantId, ...]
// Beauty
["beauty", tenantId, ...]
// Healthcare
["healthcare", tenantId, ...]
```
**Rule:** Modules MUST NOT invalidate another module's query keys.
**Current compliance:** ✅ No cross-module cache invalidation detected.
---
## 7. UI Component Boundaries
### Design system (`components/ds/`)
- Domain-agnostic primitives only
- No module-specific labels, icons, or business types
- Used by all modules
### Module design systems
| Module | Path | May import |
|--------|------|------------|
| Beauty | `modules/beauty/design-system/` | `@/components/ds`, `@/lib/utils` |
| Healthcare | `src/modules/healthcare/design-system/` | `@/src/shared/ui`, `@/lib/utils` |
| Accounting | (uses ds via `@/src/shared/ui`) | `@/src/shared/ui`, `@/lib/utils` |
**Rule:** Module DS MUST NOT import from other modules' DS or pages.
### Legacy UI (`components/ui/`)
- Platform/marketing surfaces only: homepage, auth, onboarding, dashboard
- New module code MUST NOT import from `components/ui/`
---
## 8. Known Boundary Violations
### Structural (not import violations)
| Issue | Type | Severity |
|-------|------|----------|
| Beauty at `modules/` vs Healthcare/Accounting at `src/modules/` | Path inconsistency | Low |
| Global `SiteHeader` on public module sites | Layout leak | Medium |
| `BeautyBusinessShell` deprecated but present | Dead code | Low |
| Healthcare legacy redirect pages duplicate config | Redundancy | Low |
| Beauty at `modules/` vs Healthcare at `src/modules/` | Path inconsistency | Low |
| Accounting business logic in routes | Responsibility | **Resolved** — 120 thin adapters |
### Naming inconsistencies (boundary clarity)
| Issue | Impact |
|-------|--------|
| healthcare uses `design-system/` (aligned with beauty) | Resolved in migration |
| `lib/beauty-business-nav.ts` dead file alongside `lib/beauty-portals.ts` | Stale boundary docs |
---
## 9. Enforcement Recommendations
### ESLint `no-restricted-imports` (proposed)
```javascript
// .eslintrc — example rules
{
"rules": {
"no-restricted-imports": ["error", {
"patterns": [
{
"group": ["@/components/accounting/*"],
"message": "Accounting components are not importable outside accounting module."
},
{
"group": ["@/components/beauty/*"],
"message": "Beauty components are not importable outside beauty module."
},
{
"group": ["@/src/modules/healthcare/*"],
"message": "Healthcare components are not importable outside healthcare module."
},
{
"group": ["@/components/healthcare/*"],
"message": "Legacy healthcare path — use @/src/modules/healthcare/*."
}
]
}]
}
}
```
Apply overrides for files inside each module's `app/` and `components/` trees.
### CI checks (proposed)
1. **Import graph script** — fail on cross-domain edges
2. **Route size lint** — warn if `app/**/page.tsx` > 100 lines
3. **API client size** — warn if any `lib/*-api.ts` > 500 lines
---
## 10. Adding a New Module Checklist
- [ ] Create isolated `app/{module}/`, `components/{module}/`, `lib/{module}-api.ts`
- [ ] Add BFF at `app/api/{service}/[...path]/route.ts`
- [ ] Register in `lib/apps-catalog.ts`
- [ ] Add env vars to `next.config.mjs`
- [ ] Use `components/ds/` exclusively (not `components/ui/`)
- [ ] Define query key prefix `["{module}", tenantId]`
- [ ] Add ESLint override allowing self-imports only
- [ ] Document in this file
---
## Related Documents
- [frontend-architecture-audit.md](./frontend-architecture-audit.md)
- [import-report.md](./import-report.md)
- [dependency-report.md](./dependency-report.md)
- Platform: `docs/architecture/module-boundaries.md`