dev #6
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "dev"
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?
The saved-statics sidebar needs a name and a tier per saved static and nothing else. It got there by calling GetUserSavedStatic and then Static/{uuid} once per result, and Static/{uuid} returns the full StaticDTO: every player, their whole gear set, and the entire gear option catalog per slot. Several hundred KB to render a list of names. GET api/User/SavedStaticSummaries returns {uuid, name, tier} in one response, preserving the user's saved order and dropping uuids whose static no longer exists rather than surfacing them as failures. One of the tests asserts the payload contains no playersInfoList, gearOptionPerGearType or currentGearSet, so the endpoint fails loudly if StaticDTO ever leaks back into it. The test factory also had to remap the Identity.Application and Bearer schemes onto the test auth handler, since endpoints that pin their schemes explicitly are not covered by overriding the default scheme.Gear options were embedded in StaticDTO once per player. The data is identical for every player sharing a job, changes only when an admin edits gear, and is by far the largest part of the payload — yet it was re-sent on every roster load and on every SignalR-triggered refetch, which during a raid night is once per recorded drop. Measured against a seeded 8-job party with a realistic tier catalog: static WITH options raw 151,498 B brotli 6,613 B static WITHOUT options raw 25,722 B brotli 811 B gear options, 8 jobs raw 125,576 B (now fetched once, cacheable) Cold first load moves roughly the same total bytes, since the options are still needed once. Every load after that, and every realtime refetch, drops 83% raw / 88% brotli. New GET api/Gear/Options/{tier}/{job} returns the same per-slot shape the DTO used to inline, with Cache-Control and an ETag keyed on GearCache.Version so an admin gear edit invalidates it on the next revalidation instead of waiting out max-age. GearCache now carries that version counter. GetStaticByUUID and GetSingletonPlayerInfo take includeGearOptions, default true, so existing clients are untouched; when false the field is omitted from the JSON entirely rather than serialised empty, letting a client tell "fetch these separately" from "this job has none". Building the options is skipped server-side in that case too. Tests cover the default-inlined path, the omitted path, the endpoint's shape and job filtering, and ETag revalidation returning 304.The statics list page called GET Static/{uuid} once per saved static and once per recently-visited one — a full StaticDTO each — to render member counts, alt counts, unclaimed counts and a row of role pucks. Two queries now serve the whole page. GET api/Static/Summaries?uuids=a,b,c returns roster aggregates in the order requested, dropping uuids whose static no longer exists. Recently-visited statics live in localStorage rather than on the account, so they need a batch-by-uuid endpoint; SavedStaticSummaries covers the saved ones and now shares the same StaticSummaryBuilder, so the two cannot drift. The summary carries MemberCount, AltCount, OpenClaimCount, the non-alt roster slots (id, name, job) and every player id. Names and jobs are there on purpose: the cards render initials and a role puck per slot, and dropping them would have quietly broken that. Gear is what made StaticDTO too heavy to fetch per row, and a test asserts it stays out. PlayerIds lets a client test its own claimed-player set against a static without the server needing to know that set, preserving how the page filters recents down to statics the user has not already claimed into. No authorization: GET Static/{uuid} is already unauthenticated so this exposes nothing new, but the batch is capped at 50 uuids so it cannot be turned into a bulk-enumeration tool.Measured across this API's real responses — static payloads with and without gear options, a job's gear options, and batch summaries: static (6,726 B raw) Fastest 714 B / 0.013 ms Optimal 662 B / 0.061 ms 7.3% smaller gear options (1,825 B) Fastest 276 B / 0.008 ms Optimal 235 B / 0.027 ms 14.9% smaller Optimal costs 2-5x the compression time, but that time is fractions of a millisecond, so it is a clear trade for 7-15% fewer bytes on every response. SmallestSize is deliberately not used. It reaches only ~19% below Fastest — a couple of points better than Optimal — at 150-500x the time, 8.6 ms to compress 10 KB, which extrapolates to around 100 ms on a full static payload. That is real per-request CPU for a marginal gain.The scheduling tab's reset button has been calling PUT api/Availability/ResetStaticAvailability/{staticUuid} since it shipped, but the route was never implemented. availability.service.ts catches the failure and logs it, so the button has been silently doing nothing in production — the only endpoint in the scheduling contract that was missing. Wipes every AvailabilityMark for the static: all accounts, both the typical and dated scopes. Deliberately broader than ClearMyAvailability, which is scoped to the caller and one week. Authorization matches UnclaimStaticOwnerShip/GetOwnerName rather than StaticRole.Lead. This destroys other members' data with no undo, so it stays with whoever owns the static. A static with an empty ownerIdString is rejected too — no owner means nobody is entitled to wipe it, and treating "" as unrestricted would have made unclaimed statics wipeable by any authenticated user. Broadcasts UpdateAvailability on the existing loothub group so connected clients refetch. The payload is null rather than an account id, since this is not one person's change; the client handler ignores its arguments and just refetches, so this is only a hint. Tests cover the owner path (both accounts and both scopes cleared, and only for the targeted static), the non-owner rejection, the unowned-static rejection, and an unknown static. Each seeds its own static so the destructive case cannot affect the others. Verified the authorization test is a real guard by removing the check and confirming it, and only it, fails.