perf(cms): de-duplicate per-request identity lookups (Request_Context_Bundle) - #288
perf(cms): de-duplicate per-request identity lookups (Request_Context_Bundle)#288khuepm wants to merge 2 commits into
Conversation
…_Bundle)
Implements high-load-cache-readiness Req 10 (task 11): a request-scoped
cache that lives only for one request's lifecycle and eliminates duplicate
DB reads for the same principal.
- withAuth stashes the resolved `users` row + `user_sites` membership on the
Hono context (`c.set('principal', ...)`) after it resolves them.
- withSiteMembership reads that bundle before querying, so it no longer
re-issues the same `users`/`userSites` lookups.
- withStudioAccess reuses the `access` bundle withSiteMembership already
computed instead of calling PermissionService.bundle() a second time.
Each guard falls back to querying when the bundle is absent, so middleware
stay independently correct (and standalone-testable). Guard semantics are
unchanged — a request rejected before is still rejected with the same
status code.
Adds request-context-bundle.test.ts (behavioural principal x route matrix +
query-count de-dup assertions, Req 10.3/10.4); the security-guards.wiring
tripwire is preserved.
|
Pushed ✅ "Version, typecheck, tests, and build" — fixed. The failure was in
Generated by Claude Code |
Summary
Implements request caching — a per-request de-duplication cache that lives only for the lifecycle of a single request. When the guard chain needs the same object (the caller's
usersrow,user_sitesmembership, permission bundle) more than once, it now hits the database once and reuses the cached value for the rest of the request.This is high-load-cache-readiness Req 10 / task 11 (Request_Context_Bundle). Previously
withAuth,withSiteMembership, andwithStudioAccesseach re-resolved the same identity independently.What changed:
withAuthstashes theusersrow +user_sitesmembership it already resolved onto the Hono context (c.set('principal', …)).withSiteMembershipreads that bundle before querying, so it no longer re-issues the sameusers/userSiteslookups.withStudioAccessreuses theaccessbundlewithSiteMembershipalready computed instead of callingPermissionService.bundle()a second time.Net effect: a typical authenticated request performs at most one
userslookup, oneuserSiteslookup, and onePermissionService.bundle().Loại thay đổi
perf— Cải thiện hiệu năngrefactor— Cải thiện code, không thay đổi hành vi (guard semantics unchanged)Phase / Feature liên quan
high-load-cache-readiness— Phase P1, Requirement 10 (Hợp nhất tra cứu trong middleware chain), task 11.1–11.3.✅ Definition of Done (DoD)
Code Quality
pnpm -F @lumibase/cms typecheckpass ✅)pnpm test— 299 test files passed, 1 skipped, 0 failures)Testing
request-context-bundle.test.ts(principal × route → status) — Req 10.3PermissionService.bundle()called exactly once per request — Req 10.4security-guards.wiring.test.tsgiữ nguyên pass (Req 10.2)Security
siteId; the tenant-membership gate still runsid/externalId/email/isBootstrap+ membershiproleIdDatabase / Migrations
Setup impact
n/a) — thuần code, không seed/settings/policy/wizard/capability/migrationConventional Commits
perf(cms): de-duplicate per-request identity lookups (Request_Context_Bundle)Rollback Plan
Pure middleware refactor with no schema or config change — revert the commit to restore the previous per-guard lookups. Behaviour is externally identical, so no data or client migration is involved.
Notes for Reviewers
withSiteMembershipthroughwithAuthhas already passedwithAuth's membership gate, so a cached membership is authoritative — the query only runs when no bundle was populated.withAuth'susersselects were widened by two non-sensitive columns (externalId,email) so the cached row carries everythingwithSiteMembershipneeds.Generated by Claude Code