high priority medium complexity testing pending database specialist Tier 5

Acceptance Criteria

Performance test generates and seeds 1000 activities, 100 peer mentors, and 5 chapters for a single test organization before measurement begins
Full organization export query (all activities for org, all reporting periods) completes in under 5 seconds measured from query start to last record received
Deduplication processing time for 1000 activities is measured separately and completes in under 1 second
Supabase query execution plan (EXPLAIN ANALYZE) is captured and logged for the primary activity fetch query
At least 2 database indexes are identified and applied to reduce query time — index definitions committed to migration files
Re-run of performance test after indexing shows measurable improvement (>20% reduction in query time)
Performance test results are printed to stdout in a structured format (JSON or table) for CI baseline tracking
Tests assert the 5-second threshold — test fails if exceeded, enabling regression detection in CI

Technical Requirements

frameworks
flutter_test
Supabase Dart SDK
apis
Supabase Database API (PostgREST)
Supabase SQL editor or pg connection for EXPLAIN ANALYZE
data models
BufdirActivityRecord
BufdirPeerMentorRecord
BufdirChapterRecord
performance requirements
Full org export query: under 5 seconds for 1000 activities
Deduplication pass: under 1 second for 1000 records
Seed data insertion: complete in under 60 seconds (one-time setup, not measured as part of SLA)
security requirements
Performance test runs against dedicated test Supabase instance — never against production
Seed data uses synthetic identifiers only

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

The primary performance bottleneck is almost certainly the join between activities, peer_mentors, and chapters tables filtered by organization_id. Indexes to consider: (1) CREATE INDEX idx_activities_org_period ON activities(organization_id, reporting_period_id); (2) CREATE INDEX idx_activities_peer_mentor ON activities(peer_mentor_id); (3) CREATE INDEX idx_peer_mentors_org ON peer_mentors(organization_id). Deduplication (removing double-counted activities where a peer mentor belongs to multiple chapters) should be a pure Dart operation on the fetched list — measure this separately from the DB query. Use Supabase's rpc() to call a stored procedure for EXPLAIN ANALYZE output, or connect via a raw pg connection in test-only code.

Seed data generation: use a DataFactory helper that generates realistic Norwegian activity records with proper date ranges within the reporting period. Commit index migrations as numbered SQL files in supabase/migrations/ following the project's existing migration naming convention.

Testing Requirements

Performance tests using flutter_test with Stopwatch for timing measurement. Structure as: (1) one-time setUp that inserts 1000 synthetic activities via batch Supabase inserts (use upsert in chunks of 100 to stay within rate limits); (2) timed measurement block using Stopwatch.start/stop around the BufdirActivityQueryService.fetchAllForOrganization() call; (3) assertion that elapsed milliseconds < 5000; (4) separate timed block for deduplication logic. Log Stopwatch results with print() for CI visibility. After initial run, run EXPLAIN ANALYZE via a raw SQL query through Supabase service role connection and log the plan output.

Apply identified indexes (e.g., on organization_id, reporting_period, peer_mentor_id) in a new migration file. Re-run and assert improvement. Test teardown deletes all seeded records.

Component
Bufdir Activity Query Service
service high
Epic Risks (3)
high impact medium prob technical

NHF contacts can belong to up to five local chapters simultaneously. If the deduplication logic in the activity query service incorrectly attributes cross-chapter activities, organisations will either under-report or over-report to Bufdir, which could trigger grant clawback or compliance investigations.

Mitigation & Contingency

Mitigation: Implement deduplication using the existing multi-chapter membership service as the source of truth for chapter affiliation. Write test fixtures covering all known multi-chapter edge cases and validate outputs against manually prepared reference exports from NHF.

Contingency: If deduplication cannot be made deterministic for complex hierarchies before release, gate the export behind an org-level feature flag and require NHF to validate a preview export against their manual Excel before enabling in production.

medium impact medium prob dependency

Server-side Dart libraries for Excel generation are less mature than equivalents in Node.js or Python. The chosen library may lack support for Bufdir-required formatting features (merged cells, data validation, specific date formats), requiring significant workaround effort or a library switch mid-implementation.

Mitigation & Contingency

Mitigation: Evaluate the top two Dart xlsx libraries (excel, spreadsheet_decoder) against a Bufdir template sample file before committing. Identify all required formatting features and verify library support in a spike.

Contingency: If no Dart library meets requirements, implement the Excel generation as a Supabase Edge Function in TypeScript using the well-supported ExcelJS library, exposing it to the Dart backend via an internal RPC call.

medium impact medium prob integration

The attachment bundler must retrieve documents from Supabase Storage that were uploaded by the document attachments feature. If storage paths, RLS policies, or signed URL expiry have not been standardised across features, the bundler may fail to retrieve attachments at export time.

Mitigation & Contingency

Mitigation: Audit the document attachments feature's storage schema and RLS policies before implementing the bundler. Agree on a stable internal service-account access pattern for cross-feature storage reads.

Contingency: If cross-feature storage access cannot be made reliable, implement the bundler to include only attachments that can be retrieved successfully and produce a manifest listing any attachments that could not be bundled, rather than failing the entire export.