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

9.9 KiB
Raw Permalink Blame History

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:

// 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)

// .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