Implement Hierarchy Structure Validator
epic-organizational-hierarchy-management-assignment-aggregation-task-005 — Build the validation service that enforces structural rules on the hierarchy tree: detect and prevent cycle creation when adding parent-child edges, enforce maximum depth limits (NHF 5-chapter maximum for users), validate that level types are consistent with their position in the tree, and surface constraint violations as user-readable error messages before any write occurs.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
Implement as a stateless service class HierarchyStructureValidator with only static or instance methods that accept a HierarchyTreeSnapshot value object. For cycle detection, use iterative DFS: maintain a visited set and traverse ancestors of the proposed parent; if the childId appears in the ancestor chain the edge creates a cycle. Store LevelType ordering as a const List
debugDetail). The validator should accept the full tree snapshot as a parameter rather than querying Supabase directly — callers are responsible for providing a fresh snapshot, which keeps the validator fast, testable, and free of async complexity.
Testing Requirements
Unit tests (flutter_test) are the primary testing vehicle. Test suite must include: (1) cycle detection — at least 6 cases covering no cycle, direct cycle, indirect multi-hop cycle, and self-reference; (2) depth limit — boundary tests at 4, 5 (boundary pass), and 6 (boundary fail); (3) level type consistency — one valid and one invalid case per LevelType enum value; (4) empty tree edge case. All tests must use pure in-memory tree fixtures, no Supabase calls. Aim for 100% statement coverage on HierarchyStructureValidator.
Integration test (optional): wire validator into a mock hierarchy editor flow and assert that a cycle-creation attempt is blocked at the UI layer.
Recursive aggregation queries across four hierarchy levels (national → region → local) with 1,400 leaf nodes may be too slow for real-time dashboard requests, exceeding the 200ms target and causing spinner timeouts.
Mitigation & Contingency
Mitigation: Implement aggregation as a Supabase RPC using a single recursive CTE rather than multiple round-trip queries. Pre-compute aggregations nightly via a scheduled Edge Function and cache results. For real-time needs, aggregate only the immediate subtree on demand.
Contingency: Surface a 'Refreshing...' indicator and serve stale cached aggregations immediately. Queue an async recalculation and push updated data via Supabase Realtime when ready, avoiding blocking the admin dashboard.
The 5-chapter limit and primary-assignment constraint are NHF-specific. Applying these rules globally may break HLF and Blindeforbundet configurations where different limits apply, requiring per-organization configuration that was not initially scoped.
Mitigation & Contingency
Mitigation: Make the maximum assignment count a configurable value stored in the organization's feature-flag or settings table rather than a hardcoded constant. Design the assignment service to read this limit at runtime per organization.
Contingency: Default the limit to a high value (e.g., 100) for organizations other than NHF, effectively making it non-restrictive, while keeping the enforcement logic intact for when per-org configuration is fully implemented.
The searchable parent dropdown in HierarchyNodeEditor must search across up to 1,400 units efficiently. Client-side filtering of the full hierarchy may be slow; server-side search adds complexity and latency.
Mitigation & Contingency
Mitigation: Use the in-memory hierarchy cache as the search corpus — since the cache already holds the flat unit list, client-side filtering with a debounced input is sufficient and avoids extra Supabase calls. Pre-build a search index on cache load.
Contingency: Cap the dropdown to showing the 50 most recently accessed units by default, with a 'search all' option that triggers a server-side full-text query. This keeps the common case fast while supporting edge cases.