Common Service Hierarchy Mistakes Reference
Purpose: Document anti-patterns and solutions for service hierarchy configuration.
Top 10 Hierarchy Mistakes
Mistake 1: Orphaned Child Services (No Parent)
Severity: CRITICAL
Description: Creating INVENTORY/ADDON/REGISTRY services without a parent service template.
Symptom:
- Service appears in catalogue but cannot be activated
- Error: "Parent service not found"
- Service instance has NULL parent reference
Detection Query:
SELECT code, role, parent_service_template_id
FROM cat_service_template
WHERE role IN ('INVENTORY', 'ADDON', 'REGISTRY')
AND parent_service_template_id IS NULL;
Orphaned MSN service
{
code: 'SVC_MSN_STANDARD',
role: ServiceRole.INVENTORY,
parentServiceTemplate: null // ← Orphan!
}
MSN with parent
{
code: 'SVC_MSN_STANDARD',
role: ServiceRole.INVENTORY,
parentServiceTemplate: 'SVC_MOBILE_BASE'
}
Prevention:
- Always set parent before saving service template
- Validate parent exists with referential integrity
- Use foreign key constraints in database
Mistake 2: Wrong Parent for Nested Services (NBN_AVC)
Severity: HIGH
Description: Assigning NBN_AVC to NBN_BASE instead of NBN_ACCESS.
Symptom:
- NBN_AVC activates before NBN_ACCESS
- Activation order violations
- Service hierarchy displays incorrectly
Detection Query:
SELECT st.code, parent.code as parent_code
FROM cat_service_template st
JOIN cat_service_template parent ON st.parent_service_template_id = parent.id
WHERE st.code = 'SVC_NBN_AVC'
AND parent.code != 'SVC_NBN_ACCESS';
NBN_AVC parent = NBN_BASE
<update tableName="cat_service_template">
<column name="parent_service_template_id"
valueComputed="(SELECT id FROM cat_service_template WHERE code = 'SVC_NBN_BASE')" />
<where>code = 'SVC_NBN_AVC'</where>
</update>
NBN_AVC parent = NBN_ACCESS
<update tableName="cat_service_template">
<column name="parent_service_template_id"
valueComputed="(SELECT id FROM cat_service_template WHERE code = 'SVC_NBN_ACCESS')" />
<where>code = 'SVC_NBN_AVC'</where>
</update>
Prevention:
- Document hierarchy diagrams before implementation
- Use parent selection decision tree
- Review nested services during code review
Mistake 3: PRIMARY Service with Parent
Severity: HIGH
Description: Assigning a parent to a PRIMARY (root) service.
Symptom:
- Validation error during activation
- Service cannot be purchased standalone
- Hierarchy displays PRIMARY as child
Detection Query:
SELECT code, role, parent_service_template_id
FROM cat_service_template
WHERE role = 'PRIMARY'
AND parent_service_template_id IS NOT NULL;
PRIMARY with parent
{
code: 'SVC_MOBILE_BASE',
role: ServiceRole.PRIMARY,
parentServiceTemplate: 'SVC_SOME_OTHER'
}
PRIMARY with no parent
{
code: 'SVC_MOBILE_BASE',
role: ServiceRole.PRIMARY,
parentServiceTemplate: null
}
Prevention:
- Enforce rule: role=PRIMARY ⇒ parent=null
- Add database constraint
- Validate during service template creation
Mistake 4: Wrong Role Assignment
Severity: HIGH
Description: Using wrong ServiceRole (e.g., ADDON for INVENTORY services).
Symptom:
- Inventory not allocated (INVENTORY marked as ADDON)
- Regulatory tracking missing (REGISTRY marked as ADDON)
- Billing incorrect
Detection Query:
-- Find services with inventory fields but wrong role
SELECT code, role
FROM cat_service_template
WHERE (code LIKE '%MSN%' OR code LIKE '%SIM%' OR code LIKE '%DEVICE%')
AND role != 'INVENTORY';
-- Find registry services with wrong role
SELECT code, role
FROM cat_service_template
WHERE code LIKE '%REGISTRY%'
AND role != 'REGISTRY';
Device as ADDON
{
code: 'SVC_DEVICE_MODEM',
role: ServiceRole.ADDON // ← Should be INVENTORY
}
Device as INVENTORY
{
code: 'SVC_DEVICE_MODEM',
role: ServiceRole.INVENTORY
}
Prevention:
- Use service role decision tree
- Review role assignments during design
- Validate role matches service characteristics
Mistake 5: Missing Lifecycle Inheritance Configuration
Severity: MEDIUM
Description: Child services not configured to inherit parent lifecycle events.
Symptom:
- Parent suspends but children remain active
- Parent terminates but children remain
- Manual cleanup required
Detection Query:
SELECT code, inherit_parent_lifecycle
FROM cat_service_template
WHERE parent_service_template_id IS NOT NULL
AND (inherit_parent_lifecycle IS NULL OR inherit_parent_lifecycle = false);
No lifecycle inheritance
{
code: 'SVC_MOBILE_DATA_25GB',
parentServiceTemplate: 'SVC_MOBILE_BASE',
inheritParentLifecycle: false // ← Children remain after parent terminates
}
Lifecycle inheritance enabled
{
code: 'SVC_MOBILE_DATA_25GB',
parentServiceTemplate: 'SVC_MOBILE_BASE',
inheritParentLifecycle: true
}
Prevention:
- Default
inheritParentLifecycle = true - Document exceptions explicitly
- Test parent termination flows
Mistake 6: Circular Dependencies in Constraints
Severity: HIGH
Description: Creating eligibility or activation constraints that create circular dependencies.
Symptom:
- Infinite loop during eligibility evaluation
- Stack overflow errors
- Service activation hangs
Detection Query:
-- Detect direct circular dependencies
WITH RECURSIVE deps AS (
SELECT st.id, st.code, st.parent_service_template_id, 1 as depth
FROM cat_service_template st
UNION ALL
SELECT st.id, st.code, st.parent_service_template_id, deps.depth + 1
FROM cat_service_template st
JOIN deps ON st.parent_service_template_id = deps.id
WHERE deps.depth < 10
)
SELECT * FROM deps WHERE depth > 5;
A requires B, B requires A
{
code: 'SVC_A',
eligibilityConstraints: [{ requires: 'SVC_B' }]
}
{
code: 'SVC_B',
eligibilityConstraints: [{ requires: 'SVC_A' }] // ← Circular!
}
Solution:
- Remove circular dependency
- Use one-way dependencies
- Restructure constraints
Prevention:
- Build dependency graph before implementation
- Validate no cycles during constraint creation
- Limit recursion depth in evaluation
Mistake 7: Missing Sort Order Configuration
Severity: LOW
Description: Child services without sortOrder, leading to random display order.
Symptom:
- Services display in random order
- Inconsistent UI across sessions
- Customer confusion
Detection Query:
SELECT code, parent_service_template_id, sort_order
FROM cat_service_template
WHERE parent_service_template_id IS NOT NULL
AND (sort_order IS NULL OR sort_order = 0)
ORDER BY parent_service_template_id;
No sort order
[
{ code: 'SVC_MSN_GOLD', sortOrder: null },
{ code: 'SVC_MSN_STANDARD', sortOrder: null },
{ code: 'SVC_MSN_SILVER', sortOrder: null }
]
Explicit sort order
[
{ code: 'SVC_MSN_STANDARD', sortOrder: 1 },
{ code: 'SVC_MSN_SILVER', sortOrder: 2 },
{ code: 'SVC_MSN_GOLD', sortOrder: 3 }
]
Prevention:
- Always set sortOrder for child services
- Use consistent increment (10, 20, 30) for flexibility
- Document display order requirements
Mistake 8: Mixing Inclusion Types Incorrectly
Severity: MEDIUM
Description: Using wrong inclusion type (e.g., MANDATORY for customer-choice services).
Symptom:
- Customer cannot remove unwanted service
- Free service shows as paid
- Regulatory service can be deselected
Detection Query:
-- Paid services that are MANDATORY
SELECT st.code, st.inclusion_type, c.amount
FROM cat_service_template st
JOIN cat_charge_template c ON st.id = c.service_template_id
WHERE st.inclusion_type = 'MANDATORY'
AND c.amount > 0;
-- Regulatory services that are not MANDATORY
SELECT code, inclusion_type
FROM cat_service_template
WHERE code LIKE '%REGISTRY%'
AND inclusion_type != 'MANDATORY';
Paid service as MANDATORY
{
code: 'SVC_SPEED_BOOST',
price: 10.00,
inclusionType: ServiceInclusionType.MANDATORY // ← Customer cannot opt out!
}
Paid service as OPTIONAL
{
code: 'SVC_SPEED_BOOST',
price: 10.00,
inclusionType: ServiceInclusionType.OPTIONAL
}
Prevention:
- Use inclusion type decision tree
- Review billing impact during design
- Test customer opt-out flows
Mistake 9: Forgetting Registry Services
Severity: CRITICAL (Regulatory)
Description: Creating MSN/phone number services without corresponding Registry service.
Symptom:
- IPND compliance violation
- Numbers not registered with regulator
- Audit failures
Detection Query:
-- MSN services without Registry child
SELECT msn.code
FROM cat_service_template msn
LEFT JOIN cat_service_template reg ON reg.parent_service_template_id = msn.id
AND reg.role = 'REGISTRY'
WHERE msn.code LIKE '%MSN%' OR msn.code LIKE '%NUMBER%'
AND reg.id IS NULL;
MSN without Registry
{
code: 'SVC_MSN_STANDARD',
role: ServiceRole.INVENTORY,
parentServiceTemplate: 'SVC_MOBILE_BASE'
// Missing: NUMBER_REGISTRY child service!
}
Registry service as child of parent
{
code: 'SVC_NUMBER_REGISTRY_AU_IPND',
role: ServiceRole.REGISTRY,
parentServiceTemplate: 'SVC_MOBILE_BASE',
inclusionType: ServiceInclusionType.MANDATORY
}
Prevention:
- Include Registry services in hierarchy design
- Validate Registry exists for all number services
- Automate IPND compliance checks
Mistake 10: Incorrect Activation Order
Severity: MEDIUM
Description: Services activating in wrong order due to missing dependencies.
Symptom:
- Child activates before parent
- Inventory allocated before subscription confirmed
- Billing recorded incorrectly
Detection Query:
-- Check activation order constraints
SELECT st.code, st.sort_order, parent.code as parent_code, parent.sort_order as parent_order
FROM cat_service_template st
JOIN cat_service_template parent ON st.parent_service_template_id = parent.id
WHERE st.sort_order < parent.sort_order; -- Child before parent
Child activates first
{
code: 'SVC_NBN_AVC',
activationOrder: 1 // ← Before parent NBN_ACCESS (order 2)
}
{
code: 'SVC_NBN_ACCESS',
activationOrder: 2
}
Parent activates first
{
code: 'SVC_NBN_ACCESS',
activationOrder: 1
}
{
code: 'SVC_NBN_AVC',
activationOrder: 2 // After parent
}
Prevention:
- Parent must activate before children
- Use dependency constraints for complex order
- Test activation sequences
Automated Validation Scripts
Pre-Deployment Validation
#!/bin/bash
# validate-hierarchy.sh - Run before deployment
echo "=== Service Hierarchy Validation ==="
# Check 1: Orphaned services
echo "Checking for orphaned services..."
psql -c "
SELECT code FROM cat_service_template
WHERE role IN ('INVENTORY', 'ADDON', 'REGISTRY')
AND parent_service_template_id IS NULL;
" | grep -q "0 rows" && echo "✅ No orphans" || echo "❌ ORPHANS FOUND"
# Check 2: PRIMARY with parent
echo "Checking PRIMARY services..."
psql -c "
SELECT code FROM cat_service_template
WHERE role = 'PRIMARY'
AND parent_service_template_id IS NOT NULL;
" | grep -q "0 rows" && echo "✅ PRIMARY OK" || echo "❌ PRIMARY HAS PARENTS"
# Check 3: NBN_AVC parent
echo "Checking NBN_AVC parent..."
psql -c "
SELECT st.code, p.code as parent
FROM cat_service_template st
JOIN cat_service_template p ON st.parent_service_template_id = p.id
WHERE st.code = 'SVC_NBN_AVC';
" | grep -q "SVC_NBN_ACCESS" && echo "✅ NBN_AVC OK" || echo "❌ NBN_AVC WRONG PARENT"
echo "=== Validation Complete ==="
Runtime Health Check
// hierarchy-health-check.ts
async function validateHierarchyHealth(): Promise<HealthCheckResult> {
const checks = [
checkOrphanedServices(),
checkPrimaryServices(),
checkNestedServices(),
checkRegistryServices(),
];
const results = await Promise.all(checks);
return {
healthy: results.every(r => r.passed),
checks: results,
};
}
Summary Matrix
| Mistake | Severity | Detection | Prevention |
|---|---|---|---|
| Orphaned services | CRITICAL | SQL query | FK constraints |
| Wrong nested parent | HIGH | SQL query | Decision tree |
| PRIMARY with parent | HIGH | SQL query | DB constraint |
| Wrong role | HIGH | SQL query | Role decision tree |
| No lifecycle inherit | MEDIUM | SQL query | Default true |
| Circular constraints | HIGH | Graph analysis | Cycle detection |
| Missing sort order | LOW | SQL query | Template validation |
| Wrong inclusion type | MEDIUM | SQL query | Inclusion tree |
| Missing Registry | CRITICAL | SQL query | Compliance check |
| Wrong activation order | MEDIUM | SQL query | Parent-first rule |