critical priority low complexity integration pending backend specialist Tier 1

Acceptance Criteria

At Edge Function startup, the trigger engine fetches the active scenario-evaluation config row for the target organization from the database before any evaluation loop begins
Config is stored in a typed Dart/Deno class `ScenarioEvaluationConfig` with fields: inactivityWindowDays (int), milestoneThresholds (List<int>), certificationExpiryLeadDays (int), cooldownByScenarioType (Map<String, int> keyed by scenario_type string, value in hours)
If the config row does not exist for an organization, the engine falls back to hardcoded safe defaults: inactivityWindowDays=30, milestoneThresholds=[50,100,200], certificationExpiryLeadDays=30, cooldown=72h for all types
Config is loaded once per engine invocation and passed to all evaluators — no evaluator fetches config independently
Engine startup logs the resolved config values at info level (not debug) so operators can confirm live values without verbose mode
Config parsing validates all required fields are present and of the correct type; malformed config logs a warning and uses defaults rather than crashing the engine
Unit test demonstrates that passing a custom config object to the engine changes evaluator thresholds accordingly
Config fetch uses a single DB query — not one query per config field

Technical Requirements

frameworks
Supabase Edge Functions (Deno)
apis
Supabase PostgreSQL 15
data models
activity
certification
performance requirements
Config fetch must complete within 50ms at engine startup — single indexed row lookup
Config object is passed by reference throughout the engine cycle — no re-fetching during evaluation
security requirements
Config is fetched using the service role key available only in the Edge Function environment — never via mobile client
Config data is non-sensitive (no PII) but must still be scoped by organization_id to prevent cross-org config leakage
No config values are exposed in push notification payloads sent to devices

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Store the scenario-evaluation-config in a single jsonb column or a structured row — avoid EAV (Entity-Attribute-Value) tables for config as they require N queries to assemble. A single row per organization_id with a jsonb `config` column is the simplest pattern that supports future field additions without schema migrations. In the Edge Function (Deno/TypeScript), define an interface `ScenarioEvaluationConfig` and use a parse function that applies defaults for each field individually using `?? defaultValue` — this way a partially-specified config row still works correctly.

Pass the config object as the first argument to each evaluator function rather than making it a module-level singleton — this makes unit testing evaluators trivial as each test can supply its own config.

Testing Requirements

Unit tests: verify default config is used when DB returns no row; verify config fields are correctly parsed from a mock DB response; verify malformed config (missing field, wrong type) falls back to defaults without throwing. Integration test: insert a config row in a test Supabase instance, invoke engine startup, assert the returned config matches the inserted row. Test that cooldownByScenarioType correctly maps per-type values and that missing keys default to a global fallback cooldown value.

Component
Scenario Trigger Engine
service high
Epic Risks (3)
high impact medium prob technical

The scenario-edge-function-scheduler must evaluate all active peer mentors within the 30-second Supabase Edge Function timeout. For large organisations, a sequential evaluation loop may exceed this limit, causing partial runs and missed notifications.

Mitigation & Contingency

Mitigation: Design the trigger engine to batch mentor evaluations using database-side SQL queries (bulk inactivity check via a single query rather than per-mentor calls), and add a performance test against 500 mentors during development. Document the evaluated mentor count per scenario type in scenario-evaluation-config to allow selective scenario execution per run.

Contingency: If single-run execution is insufficient, split evaluation into per-scenario-type scheduled functions (inactivity check, milestone check, expiry check) on separate cron schedules, dividing the computational load across multiple invocations.

high impact low prob technical

A race condition between concurrent scheduler invocations or retried cron triggers could cause the same scenario notification to be dispatched multiple times to a mentor, severely degrading trust in the feature.

Mitigation & Contingency

Mitigation: Implement cooldown enforcement using a database-level upsert with a unique constraint on (user_id, scenario_type, cooldown_window_start) so that a second invocation within the same window is rejected at the persistence layer rather than the application layer.

Contingency: Add an idempotency key derived from (user_id, scenario_type, evaluation_date) to the notification record insert; if a duplicate key violation is caught, log it as a warning and skip dispatch without error.

medium impact medium prob integration

The trigger engine queries peer mentor activity history across potentially multiple organisations and chapters. RLS policies configured for app-user roles may block the Edge Function's service-role queries, or query performance may degrade on large activity tables.

Mitigation & Contingency

Mitigation: Confirm the Edge Function runs with the Supabase service role key (bypassing RLS) and add composite indexes on (user_id, activity_date) to the activity tables before implementing the inactivity detection query.

Contingency: If service-role access is restricted by organisational policy, implement a dedicated database function (SECURITY DEFINER) that performs the inactivity aggregation and is callable by the Edge Function with limited scope.