When the structure type has an image, render it as a full-bleed
cover behind the page header with vertical and horizontal gradient
overlays; text shifts to white for contrast. Headers without an
image keep the previous plain layout.
With the MCP plugin enabled, payload.auth() can return a
payload-mcp-api-keys doc instead of a User. Add an isPayloadUser
type guard and use it in every server action, page, and route that
treats the auth result as a real user, so API-key sessions can no
longer pass user auth checks. hasRoles now explicitly requires a
users-collection doc.
Replace hasRoles calls with hasPermission in all server actions and page
components. Update qualification checks (logistics, intelligence) to use
permission-based checks instead of role name matching. Update staff lookup
in tickets/staff.ts to query roles collection. Use enlistmentDate field
on profile page instead of createdAt.
Tarkov-style flea market where users list locker items at a fixed price
and buyers pay through the banking system; items transfer directly
into the buyer's locker.
- market-listings + market-negotiations collections and the market page
with search/rarity filters and a Countdown timer on each card
- service lib (buyListing with partial-quantity + negotiated-price
support, clean-stock rule, creditLockerQuantity, auto pricing)
- negotiation flow: make/accept/reject/counter/withdraw, strictly-
increasing buyer offers, NPC vendor auto-resolution
- NPC vendors: game-npcs attribution, patience meter, dialogue, chat
bubbles, historical threads dialog
- 30d user / 7d auto listing durations, market-tick bin for expiry +
vendor restock, SSE notify on tick
- market event types + game-npcs/market target collections in the
event log; sidebar Market entry under Logistics
- partial-quantity purchases (buyListing/buyMarketListing/makeMarketOffer)
with full int test coverage (25 tests)
- Add resources list page with resource cards and detail pages
- Add vehicles list page with vehicle cards, filters, and detail pages
- Add ResourceCard, VehicleCard, and VehicleFilters components
- Widen structure detail page max-width from 4xl to 7xl
- New game-event-logs collection with timestamp, type, message, actor,
structure, targetCollection/targetId, and data (JSON) fields
- EventTypes constants registry for modular event category management
- emitGameEvent() utility for emitting events from server actions and hooks
- Register collection in Payload config
- Document event log system architecture in AGENTS.md
Server action: remove 'other.id === entryId' exclusion from the
split overlap scan so the source item's own footprint is treated
as occupied, forcing the split to find a different position.
UI: disable the split button via findEmptySpot check when no room
exists for the split stack, preventing a failed action.
- Move storage overview from /logistics/storage to /logistics root
- Rename page heading and sidebar label from Storage to Structures
- Update back link on structure detail page
- Remove old /logistics/storage route
- addResource, removeResource, placeResourceOnGrid, removeGridItem
now require admin or developer role (game master operations)
- transferResource, moveGridItem, mergeGridStacks, rotateGridItem,
splitGridStack, autoArrangeGrid require user, admin, or developer
(logistics operations that don't change total inventory)
- Guests are excluded from all mutating operations
Replace flat ResourceList with StructureStorageView (grid/list
toggle for structures with dimensions, flat list fallback for
non-grid structures). Apply pluralize to upkeep labels.
addResource now auto-places deposited resources onto the structure
grid (first-fit scan, fills existing stacks first, falls back to
flat-list behavior for non-grid structures).
New server actions:
- placeResourceOnGrid — explicit placement at x,y,rotated
- moveGridItem — move item to new position with optional rotation
- mergeGridStacks — merge two stacks of the same resource
- rotateGridItem — toggle rotation in-place
- removeGridItem — delete a grid entry
- splitGridStack — split a stack into two at an empty spot
- autoArrangeGrid — re-pack all items into grid