Our Angular monorepo with 360 libraries and 18 applications has architectural violations:
- 15 API libraries importing UI components (breaks build optimization/tree-shaking)
- 68 core/API files importing
@spotdraft/draftkitUI utilities - No architectural tags - all
project.jsonfiles have"tags": [] - Permissive ESLint - current rule allows
"sourceTag": "*"dependencies
// ❌ API importing UI - libs/integrations/api/src/lib/repos/integration-mapping-item.repository.ts:22
import { NATIVE_INTEGRATIONS_MAPPING_UI_FLAGS } from "@spotdraft/integrations-mapping-ui";
// ❌ API module importing UI module - libs/advanced-search/api/src/lib/advanced-search-api.module.ts:4
import { ContractGridUIModule } from "@spotdraft/contract-grid-ui";
// ❌ Core importing UI utilities - multiple files
import { isDefinedAndNotNull } from "@spotdraft/draftkit";Use Nx library tags with ESLint boundaries to enforce architectural constraints at development time.
For our existing libraries, update project.json files:
// libs/integrations/api/project.json
{
"name": "integrations-api",
"projectType": "library",
"tags": ["layer:api", "domain:integration", "scope:shared"]
}// libs/draftkit/project.json
{
"name": "draftkit",
"projectType": "library",
"tags": ["layer:ui", "domain:design-system", "scope:shared"]
}// libs/contract-counterparty/core/project.json
{
"name": "contract-counterparty-core",
"projectType": "library",
"tags": ["layer:core", "domain:contract", "scope:spotdraft-fe"]
}Replace current permissive rule in .eslintrc.json:
{
"overrides": [
{
"files": ["*.ts", "*.tsx"],
"rules": {
"@nx/enforce-module-boundaries": [
"error",
{
"enforceBuildableLibDependency": true,
"allow": [],
"depConstraints": [
{
"sourceTag": "layer:api",
"onlyDependOnLibsWithTags": ["layer:core", "layer:util", "layer:shared"]
},
{
"sourceTag": "layer:core",
"onlyDependOnLibsWithTags": ["layer:core", "layer:util", "layer:shared"]
},
{
"sourceTag": "layer:ui",
"onlyDependOnLibsWithTags": ["layer:ui", "layer:core", "layer:util", "layer:shared"]
},
{
"sourceTag": "domain:design-system",
"notDependOnLibsWithTags": ["layer:api", "layer:core"]
}
]
}
]
}
}
]
}This will prevent our current violations:
libs/integrations/apiimporting@spotdraft/integrations-mapping-uilibs/advanced-search/apiimportingContractGridUIModule
Based on our 360 libraries:
- Layer:
layer:api,layer:core,layer:ui,layer:util,layer:shared - Domain:
domain:contract,domain:auth,domain:integration,domain:design-system - Scope:
scope:spotdraft-fe,scope:embedded,scope:verifai,scope:shared - Type:
type:app,type:e2e,type:library
# 1. Bulk tag existing libraries (create script)
for lib in libs/*/project.json; do
# Add appropriate tags based on directory structure
done
# 2. Test the new rules
nx lint integrations-api # Should fail until violations fixed
# 3. Fix violations (move constants to core layer)
# libs/integrations/api -> remove UI imports
# Move NATIVE_INTEGRATIONS_MAPPING_UI_FLAGS to libs/integrations/core
# 4. Verify enforcement
nx lint --allPriority 1 - Move these to core layer:
NATIVE_INTEGRATIONS_MAPPING_UI_FLAGS→libs/integrations/coreContractGridUIModuleimports → Use core services instead- Extract
isDefinedAndNotNullfrom draftkit →libs/shared/utils
- Tags classify libraries by scope (ui/api/core) and type (component/util/data)
- ESLint rules enforce boundaries using
@nx/enforce-module-boundaries - Dependency constraints prevent invalid imports at lint time
- CI/CD integration catches violations before deployment
- ✅ Prevents architectural violations early
- ✅ Maintains clean separation of concerns
- ✅ Reduces bundle size by avoiding unnecessary dependencies
- ✅ Enables independent deployment of services
- ✅ Improves build performance