- Add Unsloth OpenAI-compatible provider with @ai-sdk/openai
- Rewrite AI generation handlers with Vercel AI SDK streaming
- Add plainTextToLexicalJson helper for richText field generation
- Configure HeadingFeature and PayloadAiPluginLexicalEditorFeature
- Stub @payloadcms/richtext-lexical server entry in client bundle
- Extract meta constants for site title and description
- Add UNSLOTH_API_KEY to .env.development
The shadcn component update pulled sidebar.tsx using Tailwind v3-style
bare-bracket custom property syntax (w-[--sidebar-width]). Under Tailwind
v4 this compiles to invalid CSS (width: --sidebar-width) which the browser
ignores, so width fell back to auto and the fixed sidebar blew out to its
content's intrinsic width (the 1372px logo header ~ half the page). The
empty spacer div was equally broken, reserving zero space and leaving the
inset m-2 margin as a stray left gap.
Three fixes:
- sidebar.tsx: wrap all 7 bare-bracket custom properties in var() so they
compile to width: var(--sidebar-width) / var(--sidebar-width-icon) /
max-width: var(--skeleton-width). The calc(var(...)) rules were already
valid; only the bare forms were broken.
- layout.tsx: replace the raw <main className="min-h-full bg-background
w-full"> with <SidebarInset>. AppSidebar uses variant="inset", whose
peer styling (md:peer-data-[variant=inset]:m-2 / :rounded-xl / :shadow)
only applies to a SidebarInset sibling, so the inset gap/rounding/shadow
were silently dropped.
- SiteHeader.tsx: replace the raw <div> + border-gray-800 + p-4 with the
standard shadcn <header className="flex h-16 shrink-0 items-center gap-2
border-b px-4"> using semantic border-b, plus -ml-1 on SidebarTrigger
and an ml-auto wrapper for NotificationsBell (which takes no className).
Verified via the running dev server: SSR HTML carries
data-variant="inset", a single <main> with the peer-data-[variant=inset]
classes, <header ... border-b>, and zero border-gray-800 occurrences.
tsc --noEmit clean for the changed files.
Import the migrations array from src/migrations/index.ts and pass it as prodMigrations to the postgres adapter. Per @payloadcms/db-postgres connect.js, when NODE_ENV=production the adapter now auto-runs payload migrate against this array on every boot, so pending migrations apply on deploy without a manual docker exec step. Idempotent on next prod boot since payload_migrations already tracks batches 1-2. DEPLOYMENT.md §7's manual 'docker exec ... payload/bin.js migrate' still works as a fallback via filesystem discovery.
Migration 7 originally bundled tickets DDL with pending schema drift, which made it fail against prod (no tickets objects existed there). Split into a stripped migration 7 (no tickets statements) and a new tickets-only migration 8 that creates enum_tickets_* types, ALTER TYPE ADD VALUE for 'tickets' + 'ticket:*' muted-type values, tickets and tickets_activity tables, and the payload_locked_documents_rels.tickets_id column + FK + index. Migration 8's .json snapshot is the new forward baseline for migrate:create (verified via zero-diff probe). Applied to prod: m1-7 baselined as batch 1, m8 applied as batch 2.
Coolify strips .git from the build context, so git CLI calls in
generate:version-info fail during Docker builds. The script now
resolves metadata in priority order: GIT_* env overrides, then
SOURCE_COMMIT (Coolify's injected build arg, shortened to 7 chars),
then git CLI fallback for local builds. Dockerfile passes the ARGs
through as ENV before the build; DEPLOYMENT.md documents the required
'Include Source Commit in Build' setting.
The generated migration added grid_x/grid_y as numeric NOT NULL without a
default, which fails on prod where game_structures_stored_resources already
has rows ('column contains null values'). Add the columns with DEFAULT 0 to
backfill existing rows, then drop the default to match the target schema.
Use the shadcn Alert component for the file-sharing hint instead of a bare Message element.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Add migration 20260816_213455 covering the Tickets collection plus all schema drift accumulated since 20260109 (banking, market, game vehicles/NPCs, attendance, enum extensions).
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Add the Helpdesk nav item with LifeBuoy icon under the core nav group.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Add the helpdesk list page and ticket detail page routes.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Add createTicket, replyToTicket, updateTicketStatus, and assignTicket server actions with notification and event-log emission.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Add the helpdesk Tickets collection with status/priority/category enums, reporter/assignee relationships, activity timeline, and closedAt lifecycle. Register in payload.config and refresh generated types.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Register a beforeNav component linking the Payload admin panel back to the public frontend.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Add a scope field to BotCommand so /signup, /link and /ping register globally (available in DMs — guild-scoped commands never appear there) while /announce stays guild-only. Migrate ephemeral replies to MessageFlags and make the /signup welcome message resilient to blocked DMs.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
- Emphasize stat values and keep labels on one line
- Rework the recent events feed into a two-line layout with human-readable type labels and narrative highlighting
- Resolve parents via subAssignments instead of inferred member overlap
- Drop cyclic or dangling subassignment edges
- Render members only at their deepest unit; widen unit boxes and pluralize member counts
- Add Account entry to the sidebar and user menu
- Hide Intelligence and Infrastructure sections unless the user is qualified
- Make the sidebar content area scrollable
- Support showing the callsign in the user menu via preferences
- Add hasIntelligenceQualification access helper
- Redirect non-qualified users away from /intelligence
- Hide mission and campaign widgets on the dashboard for non-qualified users
- Guard hasLogisticsQualification against a null user
- Add /notifications inbox with mark-read and mark-all-read actions
- Respect mutedAll/mutedTypes preferences when creating notifications
- Add View all link and Discord request label to the notifications bell
- Add trusted role and isTrusted access helper
- Add notification muting and display preferences to the user schema
- Auto-create a profile and personal bank account when a user signs up
- Add idempotent backfillProfiles seed script for existing members
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)
Developer-gated collection for NPC characters, including the vendor
fields (enabled, priceModifier, sells[]) used by the marketplace to
attribute auto-generated listings to background merchants.
- user-notifications collection (per-user inbox, owner-scoped read)
- notifyUser() fire-and-forget helper + notification label mapping
- NotificationsBell in the site header with 30s polling, unread badge,
mark-read on click, and "Mark all read"
- markNotificationsRead / markAllNotificationsRead server actions
Regenerate payload-types.ts and payload-generated-schema.ts to cover
the forthcoming user-notifications, game-npcs, and market collections
(including the quantity column on market-negotiations).
- Revert onPointerDown back to onClick for item selection
- Add error state to display server action failures to user
- Add pending state to disable buttons during submission
- Update onPick to return ActionResult for error handling
- Change onClick to onPointerDown with preventDefault on item buttons
- Also update Cancel and Clear Slot buttons for consistency
- Fixes item selection not working inside the dialog
- Change onClick to onPointerDown with preventDefault
- Prevents Tooltip from intercepting the click event
- Slot picker dialog now opens reliably when clicking hotspots
- Add arrowClassName prop to TooltipContent component
- Pass bg-popover fill-popover to wardrobe tooltip arrow
- Arrow now matches the dark tooltip body instead of being white
- Change tooltip background from bg-foreground to bg-popover (dark)
- Increase text size from text-xs to text-sm
- Add border border-border for subtle definition
- Use font-semibold for slot name label
- Wrap each wardrobe slot button with shadcn Tooltip component
- Show slot name and current item name on hover
- Use smooth fade-in/zoom-in animation from shadcn tooltip
- Position tooltip to the right of each hotspot with 8px offset
- Add attachItemFromGrid server action for drag-drop attachment
- Add attach drop detection in LockerGrid handleDragEnd
- Add attach drop styling with amber highlight on weapon footprint
- Add isAttachDrop prop to GridCell for attach-specific feedback
- Add dragError state with 5s auto-clear for attach failures
- Reuse setItemAttachment/removeItemAttachment semantics
- Handle slot replacement with no-room fallback for old attachments
- Add EquipmentEditorDialog for per-category attachments, skins, and custom names
- Add Wardrobe component with soldier image and clickable equipment slots
- Add WardrobePanel with loadout selector and current equipment display
- Add WardrobeSlotPicker dialog for equipping items from locker
- Add equip/unequip loadout functionality with equipped badge
- Add equipment schema to LockerStorages (attachments, skin, customName)
- Add wardrobe slot layout with hotspot positions for each equipment type
- Add locker:item-attach, locker:item-detach, locker:item-skin event types
- Update LoadoutCard to show equipped status and equipment list
- Update LoadoutsPanel to pass ownedItems for equipment display