high priority medium complexity infrastructure pending backend specialist Tier 2

Acceptance Criteria

Circular reference detection: attempting to set a node as its own ancestor returns a ValidationFailure with error code CIRCULAR_REFERENCE and the offending ancestor path
Max depth enforcement: organizations with type 'national' allow max 4 levels (national → region → chapter → local), 'regional' allows max 3 levels; exceeding returns DEPTH_LIMIT_EXCEEDED with current and allowed depth values
Duplicate sibling name detection: two nodes with the same name under the same parent return DUPLICATE_SIBLING_NAME with a case-insensitive match
Valid parent-child relationship: a node may only be placed under an allowed parent type (e.g. a local unit cannot be parent of a region); violation returns INVALID_PARENT_TYPE with expected parent types listed
All validation errors include a human-readable message string suitable for display in admin UI without further processing
Validator returns a typed ValidationResult sealed class: ValidationSuccess or ValidationFailure(List<HierarchyValidationError>)
Validation is pure (no Supabase I/O); all required tree state is passed as in-memory parameters to enable unit testing without database
Validation logic is reachable as a standalone Dart class importable by both service layer and future Edge Function wrappers

Technical Requirements

frameworks
Flutter
Dart
data models
assignment
contact_chapter
performance requirements
Circular reference check must complete in O(depth) time using ancestor path list; no full tree traversal required
Sibling name lookup operates on a pre-fetched List<String> passed by the caller, not a live query
security requirements
Validator must never expose internal node IDs in error messages returned to the UI; use display names only
No direct Supabase calls within validator — data access is the caller's responsibility to prevent privilege escalation

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Implement as a pure Dart class HierarchyStructureValidator with a single public method: ValidationResult validate(HierarchyValidationRequest request). The request object carries: proposedParentId, proposedChildName, ancestorPath (List of node IDs from root to proposed parent), siblingNames (List), organizationType (enum), and currentDepth (int). Use a sealed class pattern for ValidationResult to force exhaustive handling at call sites. Define HierarchyValidationError as a data class with code (enum) and message (String).

Depth limits per org type should be defined as a const Map in a constants file — not hardcoded in the validator. This makes it easy to adjust per org without touching validator logic. NHF has the deepest structure (12 national associations → 9 regions → 1400 local chapters), so depth=4 must be supported cleanly.

Testing Requirements

Unit tests covering all five constraint types (circular reference, depth limit per org type, duplicate sibling, invalid parent type, valid happy path). Each constraint test must include at least one passing and one failing scenario. Use flutter_test with mock tree data — no live Supabase connection. Test coverage target: 100% of public validator methods.

Include a test for a deeply nested valid tree (4 levels) to confirm no false positives.

Component
Hierarchy Admin Portal Screen
ui high
Epic Risks (3)
high impact medium prob security

If the AccessScopeService and the Supabase RLS policies use different logic to determine accessible units, a coordinator could see data in the client that RLS blocks server-side, causing confusing empty states, or worse, RLS could block data the scope service declares accessible.

Mitigation & Contingency

Mitigation: Define the canonical scope computation in a single Supabase Postgres function shared by both the RLS policies and the RPC endpoint called by AccessScopeService. The client-side service calls this RPC rather than reimplementing the logic, ensuring a single source of truth.

Contingency: Add integration tests that execute the same access decision through both the RLS policy path and the AccessScopeService path and assert identical results. Use these as regression guards in the CI pipeline.

medium impact medium prob integration

When a user switches active chapter via the ChapterSwitcher, widgets that are already built may not receive the context-change event if they subscribe incorrectly to the ActiveChapterState BLoC, leading to stale data being displayed under the new chapter context.

Mitigation & Contingency

Mitigation: Use Riverpod's ref.watch on the active chapter provider at the root of each scoped data subtree rather than at individual leaf widgets. Trigger a global data refresh by invalidating all scoped providers when the chapter changes.

Contingency: Add an app-level chapter-change listener that forces a full navigation stack reset to the home screen on chapter switch, guaranteeing all widgets rebuild from scratch with the new context. Accept the UX cost of navigation reset for correctness.

medium impact medium prob scope

Non-technical organization administrators may find the hierarchy management interface too complex for the structural changes they need to make frequently (e.g., chapter renaming, coordinator reassignment), leading to low adoption and continued reliance on manual processes.

Mitigation & Contingency

Mitigation: Conduct usability testing with at least one NHF administrator before finalizing the admin portal screen layout. Prioritize the most common operations (rename, reparent, add child) as primary actions in the UI. Include inline help text and confirmation dialogs with plain-language descriptions of consequences.

Contingency: Provide a simplified 'quick edit' mode that exposes only the three most common operations (rename, deactivate, add child) and hides advanced structural operations behind an 'Advanced' toggle.