Sigra.Workers.CleanupExpiredInvitations (Sigra v0.2.3)

Copy Markdown View Source

Optional Oban worker that hard-deletes expired, unaccepted invitation rows past the configured retention window (D-11).

Invariants

  • Only deletes accepted_at IS NULL rows. Accepted invitations are preserved indefinitely by this worker — they are forensic history. Host apps with stricter retention policies should configure Sigra.Audit retention, not this worker.
  • Retention window is expires_at < now() - retention_days * 86400 s. Default 30 days past expiry (see @org_config_schema :invitation_cleanup_retention_days).
  • Tenant-aware via @behaviour Sigra.Workers: the reconstructed %Scope{} carries organization_id from args so any per-batch audit event (optional) is tagged with tenant context. Q3 RESOLVED in 17-RESEARCH.md — this earns the behaviour overhead because the rows being deleted carry organization_id.
  • Inline fallback via direct-callable cleanup/3 for hosts without Oban (mirrors Sigra.Workers.AuditCleanup.cleanup/3 precedent).

Scheduling

Host apps opt in by adding this worker to their Oban cron config:

config :my_app, Oban,
  plugins: [
    {Oban.Plugins.Cron,
     crontab: [
       {"0 3 * * *", Sigra.Workers.CleanupExpiredInvitations,
         args: %{
           "organization_id" => nil,
           "actor_id" => nil,
           "repo" => "MyApp.Repo",
           "invitation_schema" => "MyApp.Organizations.OrganizationInvitation",
           "scope_module" => "MyApp.Accounts.Scope",
           "organization_schema" => "MyApp.Organizations.Organization",
           "retention_days" => 30
         }}
     ]}
  ]

Sigra does NOT auto-register this cron — host apps opt in by design.

Summary

Functions

Direct callable for the inline fallback path.

Functions

cleanup(repo, invitation_schema, retention_days)

@spec cleanup(module(), module(), pos_integer()) :: {non_neg_integer(), nil}

Direct callable for the inline fallback path.

Host apps without Oban can call this from their own scheduler (periodic GenServer, cron hit, test setup, etc.). Matches the precedent set by Sigra.Workers.AuditCleanup.cleanup/3.

Deletes invitations where expires_at < now() - retention_days days AND accepted_at IS NULL. Returns {count_deleted, nil}.