critical priority low complexity backend pending backend specialist Tier 0

Acceptance Criteria

BenefitMultiplierConfig is an immutable Dart class with fields: hourlyRateEquivalent (double), travelCostPerSession (double), publicHealthSystemCostPerHour (double), organisationId (String).
All fields are final and the class is annotated with @immutable.
fromJson(Map<String, dynamic>) correctly maps Supabase column names (snake_case) to Dart field names (camelCase).
toJson() serializes back to snake_case keys matching the Supabase column schema.
copyWith() supports selective field override.
== and hashCode are implemented covering all four fields.
A BenefitMultiplierConfig.defaults(organisationId) factory provides safe fallback values (non-zero, documented) for offline use.
All numeric fields must be positive — fromJson throws ArgumentError if any multiplier is zero or negative.
Unit tests confirm: round-trip serialization, defaults factory, and ArgumentError on invalid input.

Technical Requirements

frameworks
Flutter
flutter_test
apis
Supabase benefit_multiplier_config table (read-only consumer)
data models
BenefitMultiplierConfig
performance requirements
Serialization completes in under 1ms.
security requirements
organisationId must be treated as a non-sensitive identifier but must not be logged at INFO level in production.
Multiplier values are financial parameters — do not expose in error messages sent to external logging services.

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Place in lib/features/benefit_calculator/models/benefit_multiplier_config.dart. The Supabase table column names will likely be hourly_rate_equivalent, travel_cost_per_session, public_health_system_cost_per_hour, organisation_id — confirm with the database schema before finalizing fromJson key strings. Use (json['hourly_rate_equivalent'] as num).toDouble() for safe numeric parsing. The defaults factory is critical for offline resilience (task-003 cache fallback) — document the chosen default NOK values with a comment referencing the business rationale (e.g., national average figures).

Keep this model free of any Flutter or Supabase SDK imports so it can be tested purely with dart test.

Testing Requirements

Unit tests in test/models/benefit_multiplier_config_test.dart. Cover: fromJson with valid Supabase row shape, toJson produces snake_case keys, round-trip fidelity, defaults factory returns positive values, fromJson with zero hourlyRateEquivalent throws ArgumentError, equality and hashCode. No integration tests for this task.

Epic Risks (2)
medium impact medium prob integration

Supabase organisation configuration table may not yet have the five multiplier columns, requiring a migration. If the migration is not coordinated with other teams touching the same table, schema conflicts could delay delivery.

Mitigation & Contingency

Mitigation: Add multiplier columns in a dedicated, non-destructive ALTER TABLE migration script. Review the organisation config table schema with the backend team before writing the migration. Use nullable columns with defaults so existing rows are unaffected.

Contingency: If the migration cannot be deployed in time, stub the repository to return hardcoded default multiplier values from a local config file, allowing parallel development. Swap in the real Supabase fetch once the migration is live.

low impact medium prob scope

The ActivitySummaryAggregator depends on activity records already persisted in the database. For newly onboarded peer mentors with no activity history, the aggregator will return zero counts, which could make the calculator appear broken on first use.

Mitigation & Contingency

Mitigation: Design the pre-fill value object to distinguish between 'no data yet' and 'zero activities'. The calculator input panel should display empty inputs (not zero) when no history exists, with placeholder text guiding the user to enter values manually.

Contingency: If the distinction cannot be surfaced cleanly in the UI timeline, fall back to always showing empty inputs and document the manual-entry path as the primary UX until activity data accumulates.