Lesson 1: Canonical IDs
The Problem: ID Collisions
In a multi-repo system, multiple teams might use the same IDs:
- Repo A:
APIcontainer - Repo B:
APIcontainer - Repo C:
APIcontainer
How do we distinguish them?
Solution: Canonical IDs
Every element gets a canonical ID with format:
repo_id::local_id
Examples:
user-service::UserAPIorder-service::OrderAPIpayment-service::PaymentAPI
How Canonical IDs Work
In repo.sruja (local)
<!-- partial -->
UserService = system "User Service" {
UserAPI = container "User API" {
description "REST API for user management"
}
}
In system index (composed)
The compose process adds canonical IDs:
{
"nodes": [
{
"canonical_id": "user-service::UserAPI",
"repo_id": "user-service",
"local_id": "UserAPI",
"kind": "container",
"label": "User API"
}
]
}
Referencing Across Repos
In DSL imports
<!-- partial -->
// In order-service/repo.sruja
import { user-service } from "../bundles/user-service.bundle.json"
OrderService = system "Order Service" {
OrderProcessor = container "Order Processor"
// Use canonical reference
OrderProcessor -> user-service::UserAPI "Validates customer"
}
In queries
# Query architecture elements using natural language or patterns
sruja query "UserService" -r .
# Query with architecture file
sruja query "API" -r . -a repo.sruja
# Use why command to understand relationships
sruja why "why does OrderService depend on UserService?" -r .
ID Generation Rules
| Element Type | Canonical ID Format | Example |
|---|---|---|
| System | repo_id::SystemName | user-service::UserService |
| Container | repo_id::ContainerName | user-service::UserAPI |
| Component | repo_id::ComponentName | user-service::AuthComponent |
Best Practices
| Practice | Why |
|---|---|
| Use descriptive repo IDs | user-service not us |
| Consistent naming | Same pattern across teams |
| Don't change IDs | Breaks references |
| Document ID meaning | Helps AI editors |
Hands-On: Work with Canonical IDs
-
Publish a bundle and inspect canonical IDs:
sruja publish -r . -o repo.bundle.json cat repo.bundle.json | jq '.nodes[].canonical_id' -
Query specific elements:
sruja query "UserAPI" -r . -
Use impact analysis to see downstream dependencies:
sruja impact UserService -r . --depth 2
Learning Outcomes
- ✅ Understand what canonical IDs are and why they prevent collisions
- ✅ Explain the format
repo_id::local_idfor different element types - ✅ Use canonical IDs when referencing components across repositories
- ✅ Apply best practices for naming and maintaining IDs
Quiz: Test Your Understanding
Q1: What problem do canonical IDs solve in federated architecture?
A) They speed up bundle composition B) They prevent naming collisions when multiple repos have components with the same local name C) They encrypt sensitive architecture data D) They automatically resolve conflicts
Q2: What is the format of a canonical ID?
A) repo-id.local-id (with a period)
B) repo_id::local_id (with double colon)
C) repo-id/local-id (with a slash)
D) local_id@repo_id (with an at sign)
Q3: Why should canonical IDs remain stable once established?
A) They are used for authentication B) Changing them breaks existing references and relationships across repos C) They are stored in a database D) They are part of the Git history
Next Steps
Lesson 2 covers external references between repos.