Skip to content

The People screen forgets when somebody last signed in #465

Description

@zopeVaibhav

The People screen forgets when somebody last signed in, and removing them is one of the things
that makes it forget.
A person who signed in last week reads as "never signed in" once their
sessions are gone, which is indistinguishable from somebody who has never been here at all.

Where the value comes from

lastSignedInAt is not stored. It is computed on every read as max(sessions.createdAt)
(server/src/people/store.ts:188), over a left join to the sessions table
(server/src/people/store.ts:194). Sessions are not history — they expire, they are cleaned up, and
they are deleted outright when somebody is removed, inside the same transaction that revokes their
access (server/src/people/store.ts:302).

So the screen reports a fact about who currently holds a session and labels it as a fact about the
past. The app renders the empty case as "never signed in" (app/src/routes/_authed/admin/people.tsx:55),
which is a claim the data cannot support.

The sort makes it worse rather than hiding it: the list is ordered by that same aggregate, desc nulls last (server/src/people/store.ts:227), so a person whose sessions expired sinks to the
bottom of the screen among people who never arrived.

This deployment already knows the shape of this problem. The comment introducing sign-in audit rows
names it exactly — "whether a person somebody has just removed had ever been here, because removing
them deletes the sessions that were the only evidence" (server/src/auth/index.ts:105). The audit
trail was given a durable record. The screen an administrator actually looks at was not.

Reproduction

  1. Open People and note somebody with a last sign-in date.
  2. Delete that person's rows from sessions — or remove them through the screen, which does it for
    you, or simply wait for their sessions to expire.
  3. Reload People.

They now read "never signed in", and they have moved to the bottom of the list.

Why it matters where it does

This screen answers two administrative questions: is this account dormant, and was this person ever
actually here. Both are answered from the one field that gets erased by the ordinary lifecycle of a
session — and erased hardest by the removal an administrator performs precisely when they want the
record.

What a fix probably has to do

Store the timestamp on the person rather than deriving it from something that expires: stamp it when
a session is created, and backfill from whatever sessions still exist so a deployment upgrading does
not start from nothing.

Two things are worth getting right. The stamp must never move backwards, so a session row written
out of order cannot rewrite history. And the keyset paging currently compares against the aggregate
in a HAVING clause; moving to a stored column means moving that comparison, not just the select.

What no fix can recover is anybody whose sessions were already gone before the change lands. They
stay blank, because the evidence was deleted.

Severity

No data is at risk and nothing fails. It is a screen that answers a question wrongly, in the
direction that hides information rather than inventing it, about the people an administrator is
being asked to make decisions about.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions