ADR-0022 - Routing N-attempt editor on flat rule terminators
- Status: Accepted (2026-06-03)
- Deciders: Massimo Bagnoli
- Implementation tasks: TASK-409, TASK-410, TASK-411, TASK-412, TASK-413, TASK-414
- Supersedes: nessuno
- Superseded by: nessuno
Context
The "Routing by Destination" editor described in the product documentation, section 18.6, and present in the HTML mockup models routing as an ordered list of attempts. Each attempt contains one or more weighted trunks.
The documentation names two normalized physical tables for that structure:
routing_rule_attempts and routing_attempt_trunks. The current backend,
however, uses a flat model:
routing_rulesstores the rule-level routing configuration.routing_rule_terminatorsstores terminator assignments for each rule.routing_rule_terminators.preference_orderrepresents the attempt number.routing_rule_terminators.weightis exposed as the trunk weight percentage.
The current flat model is functionally equivalent for the documented 18.6
behavior. The documented failover_policy remains rule-level, not
attempt-level.
Decision
Implement the N-attempt UI over the existing flat model. Do not add
routing_rule_attempts or routing_attempt_trunks migrations for this editor.
The canonical mapping is:
| UI/documentation concept | Physical field |
|---|---|
attempt_order | routing_rule_terminators.preference_order |
weight_percent | routing_rule_terminators.weight |
| One attempt | Group of routing_rule_terminators rows with the same preference_order |
| Attempt trunk | One routing_rule_terminators row |
failover_policy | routing_rules.failover_policy |
For the public API and frontend terminology, preference_order is the
authoritative persisted attempt order unless a future API facade introduces an
explicit attempt_order alias.
Consequences
- No schema migration is required for the Routing by Destination editor.
- The editor can render N attempt columns by grouping flat terminator rows by
preference_order. - For percent routing, each attempt group must sum to 100 percent. This remains an application-level validation rule aligned with documentation sections 18.3 and 18.6.
- The current frontend cap of 5 terminators per rule must be removed in the UI follow-up work because it blocks N attempts times N trunks.
- Rule-level
failover_policycontinues to apply across attempts. There is no per-attempt failover policy in this model.
Conscious Deviation From Documentation
The physical tables named by the documentation, routing_rule_attempts and
routing_attempt_trunks, are intentionally not created. They are treated as a
normalized representation of behavior that the current flat model already
supports.
If a future requirement needs attempt-level metadata that cannot be represented
by grouping routing_rule_terminators rows, such as a different
failover_policy per attempt, that change requires a successor ADR before any
schema normalization is introduced.
References
- TASK-409: ADR for Routing by Destination N-attempt flat model.
- TASK-410..TASK-414: UI and validation follow-up tasks for the editor.
apps/backend/src/akira_backend/routers/routing_rules.py: flat CRUD and percent sum validation bypreference_order.apps/frontend/src/components/routing/RuleModal.tsx: existing modal already exposespreference_orderas attempt and contains the temporary 5 terminator cap to remove in follow-up work.docs/architecture/routing-model-v5.16.md: documentation section 18.6 model.