Package Dependencies
Understanding the package dependency hierarchy is crucial for maintaining the monorepo and avoiding circular dependencies.
Dependency Hierarchy
The packages follow a strict layered architecture:
┌─────────────────────────────────────────────────────┐
│ Layer 6: Applications │
│ Backend App, Front App, Dashboard App │
└──────────────────┬──────────────────────────────────┘
│ depends on
┌──────────────────▼──────────────────────────────────┐
│ Layer 5: Feature Modules & Widgets │
│ @barcoding/module-*, @barcoding/widget-* │
└──────────────────┬──────────────────────────────────┘
│ depends on
┌──────────────────▼──────────────────────────────────┐
│ Layer 4: App Core Packages │
│ @barcoding/backend-core │
│ @barcoding/frontend-core │
│ @barcoding/dashboard-core │
└──────────────────┬──────────────────────────────────┘
│ depends on
┌──────────────────▼──────────────────────────────────┐
│ Layer 3: Gridster Core (CRITICAL) │
│ @barcoding/gridster-core │
└──────────────────┬──────────────────────────────────┘
│ depends on
┌──────────────────▼──────────────────────────────────┐
│ Layer 2: Auth & Core │
│ @barcoding/auth-core │
│ @barcoding/core │
└──────────────────┬──────────────────────────────────┘
│ depends on
┌──────────────────▼──────────────────────────────────┐
│ Layer 1: SDK (Auto-generated) │
│ @barcoding/sdk │
└─────────────────────────────────────────────────────┘Dependency Rules
Rule 1: One-Way Dependencies
Dependencies always flow downward in the hierarchy. Higher layers can depend on lower layers, but never the reverse.
// ✅ Good: Higher layer depends on lower layer
// @barcoding/backend-core can depend on @barcoding/core
import { FormService } from '@barcoding/core';
// ❌ Bad: Lower layer depends on higher layer
// @barcoding/core CANNOT depend on @barcoding/backend-core
import { BackendService } from '@barcoding/backend-core'; // ERROR!Rule 2: No Circular Dependencies
Never create circular dependencies between packages.
// ❌ Bad: Circular dependency
// Package A depends on Package B
// Package B depends on Package A
// ✅ Good: Extract shared code to a lower layer
// Package A depends on Package C
// Package B depends on Package C
// Package C is independentRule 3: Respect Layer Boundaries
Packages can only depend on packages in the same or lower layers.
// ✅ Good: Module depends on core packages
// @barcoding/module-ticket
import { CoreService } from '@barcoding/core';
import { AuthGuard } from '@barcoding/auth-core';
// ❌ Bad: Module depends on another module
// @barcoding/module-ticket
import { NcrService } from '@barcoding/module-ncr'; // ERROR!Layer Details
Layer 1: SDK
Package: @barcoding/sdk
Purpose: Auto-generated API client
Dependencies: None (only Angular common and HttpClient)
Generated from: API OpenAPI spec at http://localhost:3000/openapi.json
Key Files:
services/*.service.ts- 604 API controller servicesmodels/*.ts- API model interfacesapi.module.ts- SDK module
Important: Never manually edit SDK files. Always regenerate using yarn build-sdk.
Layer 2: Auth & Core
@barcoding/core
Purpose: Universal utilities used by all three instances
Dependencies: @barcoding/sdk, Angular common
Key Exports:
FormService- Form builders and validatorsUtilityService- Helper functionsModuleStore- NGXS module stateWidgetStore- NGXS widget state- Common models and interfaces
Who uses it: All three instances, all modules, all widgets
@barcoding/auth-core
Purpose: Authentication and authorization
Dependencies: @barcoding/core, @barcoding/sdk
Key Exports:
AuthService- Authentication serviceAuthGuard- Route protectionAuthInterceptor- HTTP interceptorAuthState- NGXS auth stateAclService- Access control
Who uses it: All three instances, protected modules
Layer 3: Gridster Core
Package: @barcoding/gridster-core
Purpose: Dynamic widget system (CRITICAL - used by all three instances)
Dependencies: @barcoding/auth-core, @barcoding/core, @barcoding/sdk
Key Exports:
GridsterComponent- Main gridster componentWidgetHostDirective- Widget host directiveGridsterService- Widget management service- Widget interfaces and models
Who uses it: All three instances (Backend, Front, Dashboard)
Why it's critical:
- Widget definitions are stored in the database
- Handles dynamic widget loading and positioning
- Manages user-specific widget configurations
Layer 4: App Core Packages
@barcoding/backend-core
Purpose: Backend app-specific utilities
Dependencies: @barcoding/gridster-core, @barcoding/auth-core, @barcoding/core, @barcoding/sdk
Who uses it: Backend app, backend-specific modules
@barcoding/frontend-core
Purpose: Frontend app-specific utilities
Dependencies: @barcoding/gridster-core, @barcoding/auth-core, @barcoding/core, @barcoding/sdk
Who uses it: Front app, frontend-specific modules
@barcoding/dashboard-core
Purpose: Dashboard app-specific utilities
Dependencies: @barcoding/gridster-core, @barcoding/auth-core, @barcoding/core, @barcoding/sdk
Who uses it: Dashboard app, dashboard-specific modules
Layer 5: Feature Modules & Widgets
Feature Modules
Examples: @barcoding/module-ticket, @barcoding/module-ncr, @barcoding/module-hr
Dependencies: App cores, gridster-core, auth-core, core, sdk
Key Pattern:
// module-ticket/package.json
{
"dependencies": {
"@barcoding/core": "*",
"@barcoding/sdk": "*",
"@barcoding/auth-core": "*",
"@barcoding/backend-core": "*" // If used by Backend app
}
}Widgets
Examples: @barcoding/widget-calendar, @barcoding/widget-chart
Dependencies: gridster-core, core, sdk
Key Pattern:
// widget-calendar/package.json
{
"dependencies": {
"@barcoding/core": "*",
"@barcoding/sdk": "*",
"@barcoding/gridster-core": "*"
}
}Layer 6: Applications
Packages: Backend app, Front app, Dashboard app
Dependencies: Any package from layers 1-5
Key Pattern:
// backend/project.json
{
"dependencies": {
"@barcoding/core": "*",
"@barcoding/sdk": "*",
"@barcoding/auth-core": "*",
"@barcoding/gridster-core": "*",
"@barcoding/backend-core": "*",
"@barcoding/module-ticket": "*",
"@barcoding/widget-calendar": "*"
}
}Build Order
Due to dependencies, packages must be built in order:
# 1. Layer 1: SDK (no dependencies)
ng build @barcoding/sdk
# 2. Layer 2: Core packages
ng build @barcoding/core
ng build @barcoding/auth-core
# 3. Layer 3: Gridster
ng build @barcoding/gridster-core
# 4. Layer 4: App cores (can be parallel)
ng build @barcoding/backend-core
ng build @barcoding/frontend-core
ng build @barcoding/dashboard-core
# 5. Layer 5: Modules and widgets (can be parallel)
ng build @barcoding/module-ticket
ng build @barcoding/module-ncr
ng build @barcoding/widget-calendar
# 6. Layer 6: Applications
yarn build:back:prod
yarn build:front:prod
yarn build:dash:prodOr simply run yarn build which handles the order automatically.
Checking Dependencies
View Package Dependencies
cd web/projects/packages/@barcoding/<package-name>
cat package.json | grep -A 20 '"dependencies"'Find Who Depends on a Package
cd web
grep -r "@barcoding/core" projects/*/package.jsonVisualize Dependency Graph
cd web
npx nx graphCommon Dependency Issues
Issue 1: Circular Dependencies
Symptom: Build errors or runtime errors about circular dependencies
Solution: Extract shared code to a lower-layer package
// ❌ Bad: Package A and B depend on each other
// A → B, B → A
// ✅ Good: Extract to package C
// A → C, B → CIssue 2: Missing Peer Dependencies
Symptom: TypeScript errors about missing types
Solution: Add peer dependencies to package.json
{
"peerDependencies": {
"@angular/core": "^17.3.0",
"@barcoding/core": "*"
}
}Issue 3: Version Mismatches
Symptom: Runtime errors or type incompatibilities
Solution: Use consistent versions across packages
# Update all @barcoding packages to latest
cd web
yarn upgrade-interactive --latestBest Practices
1. Keep Dependencies Minimal
Only depend on what you actually use:
// ❌ Bad: Importing entire package for one function
import * as core from '@barcoding/core';
// ✅ Good: Import only what you need
import { FormService } from '@barcoding/core';2. Use Peer Dependencies for Angular
Angular packages should be peer dependencies:
{
"peerDependencies": {
"@angular/core": "^17.3.0",
"@angular/common": "^17.3.0"
}
}3. Document Major Dependencies
In your package README, document major dependencies:
## Dependencies
This package depends on:
- `@barcoding/core` - For form services
- `@barcoding/sdk` - For API calls
- `@barcoding/auth-core` - For authentication4. Avoid Deep Imports
Import from the package barrel, not deep paths:
// ❌ Bad: Deep import
import { FormService } from '@barcoding/core/src/lib/services/form.service';
// ✅ Good: Barrel import
import { FormService } from '@barcoding/core';Next Steps
- State Management - Learn NGXS patterns
- Creating Modules - Create new feature modules
- Testing - Test your packages