fix(manager-core): F-P-012 keyset cursor on app_user_repo::list (created_at, id) tiebreaker
ORDER BY created_at DESC, id DESC but cursor was `WHERE created_at <
$2` — when two users were created at the same instant, pagination
could skip the second row at a page boundary or return it twice.
- Add ListCursor { created_at, id } with `<rfc3339>_<uuid>` encode /
decode helpers.
- Change WHERE predicate to `(created_at, id) < ($2, $3)` matching the
ORDER BY.
- Surface the opaque cursor string through UsersListOpts /
UsersListPage / users_admin_api ListUsersResponse instead of the raw
DateTime — keeps the wire format stable while the id half stops the
boundary bug.
Same shape as F-P-005 (execution_logs).
AUDIT.md anchor: F-P-012.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -69,18 +69,20 @@ pub struct UpdateUserInput {
|
||||
pub display_name: Option<Option<String>>,
|
||||
}
|
||||
|
||||
/// Pagination knobs for `users::list`. The cursor is the `created_at`
|
||||
/// of the last row from the previous page; `None` is "first page".
|
||||
/// Pagination knobs for `users::list`. The cursor is an opaque
|
||||
/// `<rfc3339>_<uuid>` string from a previous page's `next_cursor`;
|
||||
/// `None` is "first page". F-P-012: the id half is the tiebreaker that
|
||||
/// prevents skip/duplicate at a created_at-equal page boundary.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct UsersListOpts {
|
||||
pub cursor: Option<DateTime<Utc>>,
|
||||
pub cursor: Option<String>,
|
||||
pub limit: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UsersListPage {
|
||||
pub items: Vec<AppUser>,
|
||||
pub next_cursor: Option<DateTime<Utc>>,
|
||||
pub next_cursor: Option<String>,
|
||||
}
|
||||
|
||||
/// Newly-minted session — returned exactly once by `users::login` and
|
||||
|
||||
Reference in New Issue
Block a user