Design Supabase schema for Vipps organization cost configuration
epic-bankid-vipps-login-foundation-task-006 — Create the vipps_org_cost_config table in Supabase with columns: org_id (FK to organizations), subscription_active (boolean), monthly_cost_nok (numeric), billing_contact_user_id (FK to auth.users), cost_share_model (text enum: equal_split, proportional, fixed), created_at, updated_at. Apply RLS so only org admins can update the config. Write and apply the migration. Document the cost-sharing model enumeration values agreed between the four partner organizations.
Acceptance Criteria
Technical Requirements
Implementation Notes
Use Supabase CLI migrations (supabase migration new vipps_org_cost_config). Define the cost_share_model CHECK constraint inline on the column definition rather than as a separate ALTER TABLE statement for readability. Create the update trigger using a reusable moddatetime() or a custom PL/pgSQL function if moddatetime is not available. For RLS, use (auth.uid() IN (SELECT user_id FROM org_members WHERE org_id = vipps_org_cost_config.org_id AND role = 'org_admin')) for UPDATE/INSERT policies.
Document the three cost-share model semantics clearly in a SQL comment block at the top of the migration: equal_split = total cost divided equally among active orgs, proportional = based on active user count, fixed = each org pays a fixed agreed amount regardless of usage. Coordinate with the team to confirm Vipps monthly cost range (350–750 NOK/month) matches the numeric precision chosen.
Testing Requirements
Write SQL-level tests using pgTAP or Supabase's built-in test runner to verify: (1) INSERT with invalid cost_share_model value is rejected by CHECK constraint, (2) INSERT with negative monthly_cost_nok is rejected, (3) an authenticated user from a different org cannot SELECT or UPDATE the row, (4) an org_admin can INSERT, UPDATE, and SELECT their own org's config, (5) updated_at is automatically updated on any UPDATE, (6) ON DELETE CASCADE removes the config row when the parent organization is deleted. Run migration in a clean test Supabase project to confirm idempotency.
Flutter Secure Storage behavior differs between iOS Keychain and Android Keystore — key accessibility attributes (kSecAttrAccessibleWhenUnlocked vs. WhenUnlockedThisDeviceOnly) may cause tokens to become inaccessible after device restart or OS upgrade, breaking session restoration for returning users.
Mitigation & Contingency
Mitigation: Define explicit Keychain accessibility attributes during implementation and write integration tests on both platforms. Follow flutter_secure_storage documentation for cross-platform accessibility configuration.
Contingency: Implement a recovery flow that detects secure storage read failures and falls back to full re-authentication rather than crashing. Add a migration utility to re-write tokens with corrected attributes if a misconfiguration is discovered post-release.
Personnummer is a legally sensitive national identifier under Norwegian GDPR implementation. If encryption-at-rest or data minimization requirements are not met before launch, the feature could be blocked by legal/compliance review from any of the four partner organizations.
Mitigation & Contingency
Mitigation: Ensure personnummer is only persisted after explicit user consent via the personnummer confirmation widget. Use Supabase column-level encryption for the personnummer field. Document the data processing basis and retention policy before the first TestFlight release.
Contingency: If legal review blocks the personnummer write-back, implement the feature as opt-in only with a deferred sync model, allowing BankID/Vipps login to proceed without storing the personnummer until compliance is confirmed.
If the VippsOrgCostConfig data is not populated in Supabase for all four partner organizations before the feature ships, users from unconfigured organizations will see no Vipps login option and may report it as broken, creating confusion and support load.
Mitigation & Contingency
Mitigation: Create a seed migration script for Vipps org configuration and include it in the deployment checklist. Implement a clear admin UI warning when an organization is missing Vipps configuration.
Contingency: Add a feature flag in VippsOrgCostConfig so individual organizations can be enabled/disabled without a code deploy, allowing rapid remediation.