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>
289 lines
9.9 KiB
Markdown
289 lines
9.9 KiB
Markdown
# 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) | 2–3 line re-exports | ✅ Excellent |
|
||
| Healthcare (portals/site) | 2–3 line re-exports | ✅ Excellent |
|
||
| Beauty `(owner)` CRUD | 44–245 lines inline | ⚠️ Violation |
|
||
| Accounting | 3–663 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`
|