Implement aggregation drill-down and Bufdir breakdown API
epic-organizational-hierarchy-management-assignment-aggregation-task-012 — Extend the Hierarchy Aggregation Service to produce Bufdir-compatible breakdown reports: activity counts segmented by unit level (chapter/region/national), participant deduplication across overlapping scopes, and configurable time-window filtering. Expose a query API that the Bufdir export pipeline can call to retrieve pre-aggregated metrics without re-computing the full tree walk at export time.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 5 - 253 tasks
Can start after Tier 4 completes
Implementation Notes
Implement as a Supabase Edge Function (Deno + TypeScript). Structure: (1) validate JWT and extract organization_id, (2) look up report period dates, (3) check cache for (org, unit, start, end) key, (4) on miss: load full hierarchy tree in one query using a recursive CTE (WITH RECURSIVE), compute subtree for requested unit_id, (5) load all activities in the time window for the subtree unit IDs in a single IN query, (6) deduplicate participants using a Set
For Bufdir schema mapping, load the column_mappings JSON from bufdir_column_schema and apply field name translation before returning.
Testing Requirements
Unit tests (Deno test framework): test deduplication logic with overlapping participant sets — assert national total equals union count, not sum; test time-window boundary conditions (inclusive start, inclusive end, timezone handling); test schema version mapping against multiple bufdir_column_schema versions. Integration tests: deploy Edge Function to Supabase test instance, insert known activity dataset, call endpoint and assert response counts match hand-computed values; test cache miss path (cold) and cache hit path (warm) with latency assertions; test RLS enforcement by calling with a different organization's JWT and asserting empty or forbidden response. Performance tests (see task-015): simulate 1,400-chapter tree. Mutation tests: verify that adding one activity record invalidates the correct cache entries.
Target 90%+ branch coverage on aggregation and deduplication logic.
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.