The suite could not pass on the test database: global setup now seeds the shared dev/Test123 login with a superuser Roles doc and the dashboard rank, and points its own Payload connection at the test database. Playwright runs one worker with generous test and expect timeouts because first navigation to a route triggers a cold webpack compile, and gains E2E_BROWSER_PATH to swap the browser binary when the installed Vivaldi crashes under automation. The landing page gains the missing h1 the guest specs assert, login flows wait for the redirect to land, strict-mode locator collisions get exact or level-scoped matches, the session banner test re-signs the login claims with a short expiry using the runtime secret, and the reservation dialog click forces the dispatch and verifies the dialog opened (the trigger goes aria-hidden behind the modal mid-click, which stranded the retry loop).
Pages declare brief tours in code, keyed to stable data-tour anchors. The layout resolves each visitor's access signals (intelligence and logistics qualifications, admin-panel access, feature flags) and step filtering hides what a user cannot reach, mirroring the sidebar. A tour auto-starts the first time a browser visits its page; dismissals are remembered per browser in localStorage. The header gains a replay control for on-demand runs on toured routes, the tour card gains Skip all tours on this device to opt a browser out of auto-starts, and the Account page holds the re-enable toggle. The card and spotlight get a distinct overlay treatment (glow, accent strip, outlined target).
The note and warning icons were pinned at a fixed top offset and drifted off the text line inside short callouts. They now center vertically in the callout box.
Seeded Documentation pages have no lastEditor; the index cards and the detail header now read 'System' instead of 'Unknown editor' for those. Other categories keep the old fallback.
New in-depth, non-developer guides for the core systems: logistics and storage rules, banking, market and negotiation, shipments, base management, and the map. Read stays open to any logged-in user; create and edit require admin or developer roles (enforced in the collection access functions and the wiki server actions, since the service layer runs with overrideAccess). Category escalation via update is blocked too. Ships the enum migration, regenerated schema/types, and the idempotent seed script with its markdown sources.
package.json now declares patchedDependencies, so bun install --frozen-lockfile requires patches/ to exist when the prod-deps and builder stages install. The v0.2.56 Coolify build failed with "Couldn't find patch file" because only package.json and bun.lock were COPY-ed. Verified by reproducing the failure without patches/ and a clean frozen-lockfile install (patch applied) with them.
Default compose model moves to unsloth/gemma-4-26B-A4B-it-qat-GGUF (migration rewrites plugin_ai_instructions columns + enum). Strip markdown code fences from plain-text fallbacks so Gemma's JSON-flavored answers still render as prose. Pin a bun patchedDependencies patch for @ai-stack/payloadcms (activeFieldPath context) which requires the patches/ directory alongside package.json and bun.lock. Note: the change_ai_model migration also carries the new map permission enum values from the map permission split.
Players meeting a role's minimum rank and MOS can queue for mission roles before op time. Slot holders are recomputed statelessly from signup order plus current RSVP (first N committed signups hold the role); attendance writes diff holders around the write so RSVP changes auto-promote, with notifications and events. Adds mission-role-signups collection, roleSignups/missionTime libs, sign-up panel, role slots + rich-text descriptions (with RoleDescription renderer), orphan-pruning hook, migrations, tests, and AGENTS.md docs.
Replace the maps:create/update/delete catch-all for map features: roads, zones, and nodes each take a per-collection author permission, structure placement takes maps:place (still co-gated with the logistics qualification), and GeoJSON import requires all three author permissions. The map view page keys edit UI per feature type; admin role seed grants the new values. Tests updated for the permission split.
Touch drags flip pages: the page follows the finger live, the axis locks
on first movement so vertical pans never flip, and edge drags get
rubber-band resistance. Swipes starting on interactive controls are
ignored. Swipe intent lives in bookSwipeDirection with unit tests.
Chapter numbers now follow the order beats were written: sortBeats
defaults to creation date ascending, treats occurredAt as display-only,
and lets an explicit Order value curate the sequence. The /story page
shows the newest chapter on top with correct numbering, and switches to
exact hand-sequenced book mode when any beat is ordered.
Fullscreen reader alongside Immersive view: paginated two-page spread
with no vertical scroll, chevron and arrow-key page turns, and a page
indicator. Chapters always render in reading order (Chapter 1 first).
Layout knobs (spine gap, single-column breakpoint, book max width) live
in lib/story/bookLayout with unit-tested paging math.
- Introduced voiceover relationship to StoryBeats with AI-generated flag.
- Added BeatVoiceover component for playing audio narrations with a minimal interface.
- Updated StoryPage, StoryViewer, and StoryTableOfContents to display and handle voiceovers.
- Created Voiceovers collection for uploading and managing audio narrations for beats.
- Included migration script to support voiceover functionality in the database.
The one-shot heads-up toast used duration:Infinity with no id, so it
lingered after auto sign-out (when the banner unmounts) and its Extend
button 403'd on the expired token. Give the toast a stable id and
dismiss it when the banner leaves the warn window or unmounts, matching
the MissionReminderToasts pattern.
- getPendingSurveys resolves open + eligible + unsubmitted surveys (single eligibility path shared with the list page)
- GET /api/surveys/pending poll endpoint (cookie auth)
- SurveyReminderToasts in the frontend layout: polls every 5 min, toasts at most once per 15 min, action deep-links into the modal
- integration coverage for the pending resolution
- list page and detail page use the standard site page wrapper (icon + title + subtitle)
- card click opens the survey in a scrollable shadcn Dialog; submitting removes the card on close
- detail page matches the helpdesk pattern: back link, title block, form in a card
- /surveys?open=<id> deep link auto-opens the modal; SurveyForm gained onSuccess
- forms collection: targeting group (all/users/roles/qualifications), activeFrom/activeUntil window, radio/date field blocks enabled
- form-submissions: server-side user attribution, expiry and audience gates, one attempt per user
- forms/submissions permissions in the Surveys registry group + admin role seed grants
- frontend /surveys list and /surveys/[id] take page with client block renderer
- register the pending role permission enum values migration
- announcements collection: info/success/warning/error variants, banner/modal/dialog/toast display types, up to 3 action buttons, dismissible flag, activeFrom/activeUntil windows, audience targeting (all/users/roles) and path include/exclude matching copied from the Shims pattern
- pure client-safe evaluation lib (enabled, time window, audience via roleDoc IDs, path match) plus per-browser localStorage dismissals
- AnnouncementHost mounted in the (frontend) layout: banners render inline, toasts via sonner custom markup, modals and confirmation dialogs queue one at a time
- permissions announcements:create/read/update/delete + admin:announcements:manage
- description is Lexical richText rendered via RichText/lexical-content on all surfaces; role targeting uses the dynamic Roles collection
- hand-written migrations with snapshot sidecars (collection, roleDocs targeting, description richtext conversion) + integration tests (12 passing)
Create /app/public/tiles in the runner image, bind-mount it in compose, and document the Coolify volume plus upload steps; restructure .gitignore (test artifacts, /public/tiles, backups).
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Bootstrap a per-run test database (ensure, push schema, truncate, seed baselines, repair sequences), wire vitest/playwright globals, and gate schema push behind DB_PUSH. Serial test files share the one database.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>