Skip to content

[P2] Delete invites when they are accepted, and sweep the expired ones #103

Description

@baronunread

Problem

invites keeps every row forever. An accepted invite stays, with its token and
the invited email address, and so does one that nobody ever opened.

Nothing reads that history. Every reader filters it back out:

  • src/worker/routes/orgs.ts:307 filters !r.acceptedBy && r.expiresAt > ts for the list.
  • orgs.ts:324 filters accepted_by is null when checking for a duplicate invite.
  • orgs.ts:583 and orgs.ts:994 both re-check invite.acceptedBy || invite.expiresAt < Date.now().

So the column exists to be excluded four times, and the rows exist to be
skipped.

Why it matters

A spent invite token and the email it was sent to sit in D1 with no expiry.
That is retention nobody asked for, on the one table that holds an address
belonging to someone who may never have signed up.

Plan

  • On accept (inviteRoutes.post("/:token/accept"), orgs.ts:1002), insert the
    membership and delete the invite in one D1 batch, instead of setting
    accepted_by.
  • Delete expired invites in the existing scheduled cleanup.
  • Drop invites.accepted_by in a migration, and the four filters with it.
  • If invite history turns out to be wanted later, it belongs in admin_actions
    or an org activity log, not in a live-lookup table.

Acceptance criteria

  • Accepting an invite leaves no invites row.
  • A second accept of the same token gets the same answer as an unknown
    token, so nothing learns which tokens existed.
  • Expired invites are gone after the sweep.
  • The pending-invite list and the duplicate-invite check no longer filter
    on accepted_by.
  • e2e scenario in tests/e2e/.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions