refactor(server): standardize handler check order; unify pagination (#89) #109
No reviewers
Labels
No labels
area:api
area:core
area:docs
area:infra
area:ux
dependencies
documentation
duplicate
good first issue
help wanted
invalid
question
rust
status:complete
status:partial
status:planned
type:bug
type:design
type:feature
type:infra
type:refactor
type:refactor
type:research
type:ux
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
icub3d/decentcom!109
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feature/89-check-order-pagination"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Finishes #89. Five of its six checklist items (thiserror,
new_idfallback,parking_lot,event_jsonwarn, targeteddead_codeallows) already landed via #107 — this PR completes the remaining one: standardize check ordering and unify the pagination envelope /aftercursor.Closes #89.
Check ordering
The canonical order is now documented in
crate::permissions: feature flag → auth/read-only/membership (extractors) → parent-resource existence → permission → input validation → target existence → object-level guards.Deviations fixed (found by a full audit of all ~66 handlers):
create_threadwas gated on themessage_threadsflag —get_thread,list_thread_messages,create_thread_message,follow/unfollow/mark_readall bypassed it. All thread routes are now gated (newrequire_feature()helper incrate::error, also adopted by attachments and reactions).404 channel not foundinstead of falling through to404 message not found.create_threadlikewise never verified the path channel.update_channel/delete_channelnow return an explicit404 "channel not found"rather than the generic storage-layer"not found".ensure_channel_exists()helper (inchannels, re-exported crate-wide) replaces the copies inmessagesandattachments.Pagination
aftercursor implemented for channellist_messages(it was accepted-then-rejected with a 400, while the thread-messages endpoint honored it via the sameListMessagesQuery). The sqlite query mirrorslist_thread_messages:afterpages oldest-first,beforenewest-first,beforewins if both are given.list_reactors: itstotalfield was just the returned page length — misleading, and nothing (client or SDK) consumed it. Replaced with the standard fetch-limit+1has_more, matchingMessagePage. TheListReactorsQuery/ReactorEntry/ListReactorsResponsetypes were hand-duplicated in server, Rust SDK, and web client; they now live inshared::rest(per the #82 direction) and the SDK re-exports them.list_thread_messagesnow uses the batchedenrich_messages()(3 queries per page) instead of the per-message loop (3 queries per message) — same fix #84 made for channel messages.Not changed (noted from the audit, out of scope)
create_invitereturns 400 for a missinggrant_role_id;preview_inviteuses 410 — left as-is.Verification
cargo test --workspace— 209 passed, including 5 new regression tests (after-cursor paging, thread-route feature gating, reactions channel-404, reactorshas_more, channel update/delete 404)cargo clippy --workspace --all-targets -- -D warnings,cargo fmt --check— cleanpnpm lint,pnpm test(89 passed) — clean🤖 Generated with Claude Code