97454f361b9f3a395ecf532b5fac3c50904c9129
1833
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
97454f361b |
feat(home): rebuild the landing page on a shared panel system
CI / check (push) Successful in 32s
CI / tests-unit (push) Successful in 2m12s
CI / tests-integration (push) Successful in 2m43s
CI / tests-imaging-browsers (push) Successful in 2m10s
CI / preflight (push) Skipped
CI / tests-ui (push) Successful in 4m22s
CI / tests-quality (push) Successful in 1m32s
CI / deploy (push) Successful in 3m1s
The homepage mixed four different translucent washes (surface 44-60% plus a backdrop-filter each), rendered the same four counters twice, and showed a dangling "Welcome to " eyebrow because the localized string expected the hotel name. A missing theme wallpaper replaced the whole sky gradient with flat white, and stale CMS image references produced broken images and 404s. Replace the ad-hoc panels with one opaque, theme-derived `.panel` token set (surface, border, shadow, header, radius) and a `.panel-float` variant for the counter strip that straddles the hero edge. The strip is now the single home of the four headline counters; a failed read renders "unavailable" instead of silently dropping a cell. Add the fourth feature card (Games) that already had translated copy, link recent users to their profiles, and fall back to themed placeholders for news covers and camera photos without an upload. Add `pages.home.heroEyebrow` to all 25 locales, layer the CMS wallpaper over `--site-bg-gradient` instead of replacing it, and keep the sky in dark mode. Add `publicAssetExists` so local uploads that no longer exist are skipped (wallpaper, help topics) rather than rendered broken. Fix the `/help` topic icons to use the `/assets/images/help-center/` base the detail page already used. Throttle the spotlight glow to one update per animation frame, drop the dead `.glass-chip` rules, define the missing `.panel-float`, and fix the stat divider and reduced-motion selectors. Stat labels use the readable text token so they clear WCAG AA, and the language button's accessible name now contains its visible label. Verified: tsc, biome, 3590 unit tests, i18n audit unchanged, axe 0 violations at 390/768/1024/1280/1440 in light and dark, quality e2e 16/16. |
||
|
|
ecd8e5852c |
perf(build): keep test suites out of the image and cache CI builds durably
CI / check (push) Successful in 30s
CI / tests-unit (push) Successful in 1m53s
CI / tests-integration (push) Successful in 1m54s
CI / tests-imaging-browsers (push) Successful in 2m26s
CI / tests-quality (push) Successful in 2m19s
CI / tests-ui (push) Successful in 4m31s
CI / preflight (push) Skipped
CI / deploy (push) Failing after 3m9s
Three build-time improvements, all measured on this host. The build context no longer ships the test suites. `next build` type-checks the whole project, so `e2e/` and `integration/` in the context made the image build fail on a type error in test code and pulled @playwright/test, vitest, msw, testcontainers and drizzle-kit into the image. The CI runs those suites on the host. Type-check time in the build drops from 2.2s to 1.3s, and a contract test now fails if application code ever imports from those folders. The CI now exports the build cache to a directory outside the runner workspace: /var/cache/epicnext-cms-buildcache for the release and a separate map for branch preflights, so a branch can never feed the release cache. The workspace is wiped after every job and `docker builder prune` runs after every release, so the next build started with an empty cache and downloaded all 493 packages again (measured: reused 0, downloaded 493). With the durable export the frozen dependency layer is reused (measured: reused 493, downloaded 0) even after a full prune. A cache directory that is not writable only produces a warning; the release is never blocked. Investigated the remaining ~30s of Next.js build tracing: excluding the dev-only packages with `outputFileTracingExcludes` made it slower (35s vs 30s), because the traced output was already minimal (5 packages). The cost is Next's own page-config collection and file tracing over 329 routes, not the dependency set, so no configuration was kept. |
||
|
|
8ca538f99f |
perf(build): resolve pnpm from the pin and reuse the real pnpm store
CI / check (push) Successful in 29s
CI / tests-integration (push) Successful in 2m13s
CI / tests-unit (push) Successful in 2m28s
CI / tests-imaging-browsers (push) Successful in 2m29s
CI / preflight (push) Skipped
CI / tests-quality (push) Successful in 55s
CI / tests-ui (push) Successful in 5m10s
CI / deploy (push) Successful in 3m47s
The Docker build was slower than it needed to be and could drift away from the lockfile. Three separate causes, fixed together. The image installed a pinned [email protected].1 while package.json pins 12.11.2 through `packageManager`. pnpm silently self-managed the difference at build time: it downloaded the right version into an uncached location and never verified the sha512 hash. Install corepack instead and let it resolve version and hash from the pin, so the image can no longer diverge and a tampered tarball is rejected. The resolved pnpm lives in COREPACK_HOME inside the image, so the migrations image still runs pnpm offline (`docker run --entrypoint pnpm ... db:migrate`). The pnpm store cache-mount pointed at /root/.local/share/pnpm/store, but pnpm keeps its store in $PNPM_HOME/store/v11. The mount was a no-op: every build re-downloaded all 493 packages ("reused 0, downloaded 493"). Mounting the store where pnpm actually keeps it turns that into "reused 493, downloaded 0". The build context carried backups/ (232MB of rotating database dumps) and public/vendor/ (regenerated by `pnpm assets:editor` from node_modules). Both grew the context and invalidated the `COPY . .` layer on every daily backup rotation, forcing a full Next.js rebuild. Excluding them takes the context from 276MB to 23MB. Compose now also exports the build cache to .docker-cache/cms and imports it again, so the cache survives `scripts/docker-prune.sh`, which trims the daemon cache to 4GB after every deploy. Verified by pruning the entire daemon cache: the next build restored every layer from the local export and downloaded nothing. Also: byparr's floating `:latest` tag is now pulled on every start, the migrations build in scripts/docker-update.sh imports the same local cache, the README no longer claims the build needs host networking or an iptables-disabled daemon, the pnpm rationale in renovate.json reflects that Docker follows the pin automatically, and contract tests pin the new invariants so the store path cannot drift back. |
||
|
|
1e81cac504 |
test(ui): isolate the fixture port so parallel runs stop colliding
CI / check (push) Successful in 29s
CI / tests-imaging-browsers (push) Successful in 1m37s
CI / tests-unit (push) Successful in 2m4s
CI / tests-integration (push) Successful in 2m12s
CI / preflight (push) Skipped
CI / tests-quality (push) Successful in 55s
CI / tests-ui (push) Successful in 4m31s
CI / deploy (push) Successful in 3m39s
The self-hosted CI runner packs several jobs onto the shared host network (capacity 4). The UI suite pinned the fixture server to 127.0.0.1:3107 and set reuseExistingServer: true, so overlapping runs fought over the bind: one job won it, and every browser in the other got "connection refused" on all four projects. Pass one random high port per run through the environment (shared by the main process and its worker) and only reuse an existing server outside CI. Verified with the full ui suite: 150 passed, 2 skipped. |
||
|
|
3bc218ba16 |
chore(deps): dedupe the lockfile to the newest transitive versions
CI / check (push) Successful in 33s
CI / tests-integration (push) Successful in 1m58s
CI / tests-unit (push) Successful in 2m6s
CI / tests-imaging-browsers (push) Successful in 1m5s
CI / preflight (push) Skipped
CI / tests-quality (push) Successful in 52s
CI / tests-ui (push) Failing after 6m11s
CI / deploy (push) Skipped
`pnpm dedupe --check` still flagged strtok3 10.5.0 (via file-type 22.2.0) against the 10.6.2 already in the graph. Collapse it so the lockfile resolves every transitive dependency to the highest version its parents allow; the check is now clean and the full unit suite still passes. |
||
|
|
61f4db2a00 |
chore(deps): update dependencies to the latest releases
CI / check (push) Successful in 28s
CI / tests-imaging-browsers (push) Successful in 1m42s
CI / tests-integration (push) Successful in 2m30s
CI / tests-unit (push) Successful in 2m55s
CI / preflight (push) Skipped
CI / tests-quality (push) Successful in 1m20s
CI / tests-ui (push) Successful in 6m1s
CI / deploy (push) Successful in 21s
Bump every direct dependency to the newest published version, including the @hookform/resolvers 5 -> 6 major. The zodResolver API used by the admin room and user edit forms is unchanged, and typecheck plus the full unit suite pass on the new resolver. Highlights: next 16.4.2, react-query 5.104.4, react-virtual 3.14.21, motion 14.4.0, lucide-react 1.59.0, isomorphic-dompurify 4.6.0, resend 6.34.1, music-metadata 12.2.3, vitest / coverage-v8 5.0.5, postcss 8.5.31 and @axe-core/playwright 4.14.0. README core-stack versions are re-synced. |
||
|
|
597287fce5 |
fix(compose): keep the CMS opt-in so it cannot claim the CI port
CI / check (push) Successful in 36s
CI / tests-imaging-browsers (push) Successful in 1m49s
CI / tests-integration (push) Successful in 1m59s
CI / tests-unit (push) Successful in 2m4s
CI / preflight (push) Skipped
CI / tests-quality (push) Successful in 42s
CI / tests-ui (push) Successful in 4m39s
CI / deploy (push) Successful in 3m20s
On a CI-managed host scripts/ci-deploy.sh owns port 3002 through the blue/green slots, so a compose replica of the cms service could only ever crash-loop on EADDRINUSE — it never serves traffic, because nginx points at a slot container. Gate the service behind the `cms` profile so a bare `docker compose up -d` starts only byparr. Naming the service explicitly (`docker compose up -d cms`, which is what the installer and updater already do) still enables the profile automatically, so the compose-only install path keeps working. Keep the one port that is actually served (3002) and make the 2 GB ceiling hard by capping swap at 2g as well. Drop the green compose service (3003): the green slot only ever exists as a docker run container created by CI, so compose no longer defines it and the two paths cannot drift apart. The loopback override contract stays covered: proxy-config.test.mjs now renders the configuration with --profile cms, and a new build-contract test pins the profile and the memory limits so neither can be dropped by accident. |
||
|
|
5c428c4526 |
feat(home): label the top-bar online counter with the hotel name
CI / check (push) Successful in 33s
CI / tests-integration (push) Successful in 1m58s
CI / tests-unit (push) Successful in 2m1s
CI / tests-imaging-browsers (push) Successful in 1m24s
CI / preflight (push) Skipped
CI / tests-quality (push) Successful in 50s
CI / tests-ui (push) Successful in 4m34s
CI / deploy (push) Successful in 3m12s
Use the shared LiveOnlineCount so the landing top bar reads "0 <hotel> online" instead of a bare number, and drop the hotel name from the left (the logo stays) so it is not shown twice. |
||
|
|
e7a6b2b602 |
style(home): tidy hero spacing and top-bar online badge
CI / check (push) Successful in 28s
CI / tests-imaging-browsers (push) Successful in 1m32s
CI / tests-integration (push) Successful in 1m49s
CI / tests-unit (push) Successful in 1m55s
CI / tests-quality (push) Successful in 50s
CI / tests-ui (push) Successful in 5m1s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 2m24s
Drop the orphaned h1 margin left over from the removed hero online chip, and the stray title attribute on the top-bar online indicator. |
||
|
|
4b25292ecc |
feat(site): hide global chrome on landing pages
CI / check (push) Successful in 28s
CI / tests-imaging-browsers (push) Successful in 2m7s
CI / tests-unit (push) Successful in 2m23s
CI / tests-integration (push) Successful in 2m22s
CI / preflight (push) Skipped
CI / tests-quality (push) Successful in 52s
CI / tests-ui (push) Successful in 5m14s
CI / deploy (push) Successful in 3m43s
The index, login and register render their own AuthTopBar, so the shared TopHeader / SiteHeader banner / Navigation duplicated the same chrome. Hide the global chrome on those three standalone landing pages only. |
||
|
|
b40293bd06 |
feat(home): clean shared top bar with live online counter
CI / check (push) Successful in 28s
CI / tests-imaging-browsers (push) Successful in 1m34s
CI / tests-integration (push) Successful in 1m57s
CI / tests-unit (push) Successful in 2m1s
CI / tests-quality (push) Successful in 50s
CI / tests-ui (push) Successful in 4m39s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 3m29s
The homepage duplicated the online count and recent-user avatars (hero plus community sidebar), and the public pages each kept their own chrome. Put one AuthTopBar at the top of index, login and register — logo + hotel name plus a live online indicator and the language/clock/theme controls — and drop the duplicated hero rows. |
||
|
|
9cf1eb615c |
feat(auth): make password length configurable via env (min 5–30, max 30–128)
CI / check (push) Successful in 29s
CI / tests-imaging-browsers (push) Successful in 1m46s
CI / tests-integration (push) Successful in 1m47s
CI / tests-unit (push) Successful in 1m49s
CI / preflight (push) Skipped
CI / tests-quality (push) Successful in 44s
CI / tests-ui (push) Successful in 4m38s
CI / deploy (push) Successful in 3m38s
Add PASSWORD_MIN_LENGTH / PASSWORD_MAX_LENGTH (validated in src/env.ts) and a
shared passwordPolicy helper. The policy drives the zod schemas in register,
password reset and the admin create-user dialog, plus the live requirement
checks and strength meter in the register form.
Locale messages now interpolate the configured minimum via {min} instead of
hard-coding 12.
|
||
|
|
aef0939ee9 |
refactor(auth): share the auth landing and extract AuthField
CI / check (push) Successful in 36s
CI / tests-imaging-browsers (push) Successful in 1m36s
CI / tests-integration (push) Successful in 1m52s
CI / tests-unit (push) Successful in 1m57s
CI / tests-quality (push) Successful in 52s
CI / tests-ui (push) Successful in 4m46s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 3m40s
The login and register pages were near-identical after the previous cleanup, and both forms repeated the same labelled, icon-prefixed input seven times. Move the data loading and page shell into auth-landing.tsx (loadAuthLanding + AuthLandingView) and the input markup into a single AuthField, so the pages become thin compositions and every field shares one focus, icon and aria implementation. The numbered section headers collapse into AuthSectionHeader. No behaviour change. |
||
|
|
c6e5e0b1a9 |
feat(auth): unify and polish login, register and homepage auth UI
CI / check (push) Successful in 35s
CI / tests-imaging-browsers (push) Successful in 1m34s
CI / tests-integration (push) Successful in 2m1s
CI / tests-unit (push) Successful in 2m11s
CI / tests-quality (push) Successful in 52s
CI / tests-ui (push) Successful in 5m7s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 4m11s
Login and register each carried their own copy of the promo panel and the error banner, so the two pages drifted apart and every caller had to wire role="alert" by hand. Extract a shared AuthPromoCard and AuthAlert, use them in both forms and for the login notices, and link errors to their fields via aria-invalid / aria-describedby. Focus now lands on the 2FA code field the moment it appears, the credential fields lock while a request is in flight, and invalid inputs get a danger tint. The homepage top bar was a byte-for-byte duplicate of AuthTopBar; it now renders the shared component, and the compact homepage login uses the tighter spacing its comment already promised. |
||
|
|
2249303dbd |
chore(lint): remove dead eslint-disable directives
CI / check (push) Successful in 30s
CI / tests-imaging-browsers (push) Successful in 1m31s
CI / tests-unit (push) Successful in 1m45s
CI / tests-integration (push) Successful in 1m49s
CI / preflight (push) Skipped
CI / tests-quality (push) Successful in 47s
CI / tests-ui (push) Successful in 4m24s
CI / deploy (push) Successful in 3m39s
The project lints with Biome only, so none of these 78 directives across 57 files ever suppressed anything. Directives that carried the rationale for a flagged dynamic index access keep that rationale as a plain comment. |
||
|
|
07c5904879 |
test: make coverage opt-in and ratchet thresholds to the measured floor
Coverage was enabled by default, which forced v8 instrumentation on every run and made a focused `vitest run <file>` fail the global thresholds that a single file can never satisfy. `pnpm test:coverage` now opts in explicitly while `pnpm test` stays fast. Thresholds ratcheted from 36/29/30/37 to the measured full-suite floor of 37/30/31/38, so a drop in coverage fails again. Also drops a stale comment about a parent Laravel repo and a dead .next.prev exclude from the config. |
||
|
|
4776a41c01 |
fix(env): align suggested DB pool size with MariaDB max_connections
The example .env suggested DATABASE_POOL_SIZE=150 and connection_limit=150. MariaDB defaults max_connections to 151, so a single CMS instance could claim the server's entire connection budget, starving the emulator and any second instance. The README already documents a pool size of 25; the example now matches and notes that DATABASE_POOL_SIZE is the value that actually applies. |
||
|
|
a32cf6119b |
perf(build): measure the homepage and fix optimizePackageImports
/ is the highest-traffic route but was missing from both the public-route instrumentation and the JS size budgets, so a payload regression there could never fail the build. It is now wrapped in withPublicPagePerformance and budgeted alongside the other public routes. optimizePackageImports listed date-fns, which is not a dependency (a no-op), while omitting the barrel-heavy packages that are actually imported: motion, @dnd-kit/core, @dnd-kit/sortable and @tanstack/react-virtual. |
||
|
|
bb3799f705 |
perf(i18n): stop serializing the full catalogue on public pages
The root layout fed the entire ~254 KB message catalogue to NextIntlClientProvider, which serializes it into the RSC payload of every page. A public page only reads ~59 KB of it; the ~195 KB difference is staff tool copy that only /admin, /admin-next and /mod ever render. The root provider now installs the reduced catalogue and each staff route group re-installs the full one, since a nested NextIntlClientProvider replaces the parent message set rather than merging into it. pages.admin.actions stays public because the shared useServerAction hook runs on public pages too. Measured: 253 KB -> 59 KB of messages per public page (raw JSON). Guard tests cover all three halves: the root keeps using the reduced catalogue, every staff layout installs its own full provider, and no public tree reads a staff-only namespace. |
||
|
|
d28dde459a |
perf(auth): memoize auth() per request with React cache
A single authenticated render called auth() 4-5 times (access guard, site layout, both permission loaders, the page itself), and every call re-parsed the session cookie, decoded and HMAC-verified the JWT and ran the jwt/session callbacks. Wrapping NextAuth's handler in React's cache scopes that work to one verification per request. Outside a render (scripts, jobs worker) React's cache is a pass-through, so those call sites behave exactly as before. |
||
|
|
095353012a |
fix(build): suppress circular-chunk warning (server-only, no runtime impact)
CI / check (push) Successful in 32s
CI / tests-imaging-browsers (push) Successful in 1m53s
CI / tests-integration (push) Successful in 2m4s
CI / tests-unit (push) Successful in 2m47s
CI / preflight (push) Skipped
CI / tests-quality (push) Successful in 1m12s
CI / tests-ui (push) Successful in 5m49s
CI / deploy (push) Successful in 3m29s
|
||
|
|
ef0c425598 |
fix(redis): skip missing-REDIS_URL warning during production build
CI / check (push) Successful in 40s
CI / tests-integration (push) Successful in 2m15s
CI / tests-unit (push) Successful in 3m7s
CI / tests-imaging-browsers (push) Successful in 1m36s
CI / tests-quality (push) Successful in 1m14s
CI / tests-ui (push) Failing after 6m56s
CI / preflight (push) Skipped
CI / deploy (push) Skipped
|
||
|
|
8d3263a8fe |
feat(i18n): translate dashboard and home/profile strings for nl
CI / check (push) Successful in 39s
CI / tests-imaging-browsers (push) Successful in 1m51s
CI / tests-integration (push) Successful in 2m19s
CI / tests-unit (push) Successful in 3m9s
CI / preflight (push) Skipped
CI / tests-quality (push) Successful in 1m32s
CI / tests-ui (push) Successful in 7m6s
CI / deploy (push) Successful in 21s
|
||
|
|
050fcdf25b |
feat(i18n): wire header strings to translations across locales
CI / check (push) Successful in 34s
CI / tests-imaging-browsers (push) Successful in 2m7s
CI / tests-integration (push) Successful in 2m18s
CI / tests-unit (push) Successful in 3m8s
CI / preflight (push) Skipped
CI / tests-quality (push) Successful in 1m20s
CI / tests-ui (push) Successful in 5m45s
CI / deploy (push) Successful in 3m10s
|
||
|
|
a40669b130 |
feat(i18n): add header menu keys to all locales
CI / check (push) Successful in 31s
CI / tests-imaging-browsers (push) Successful in 1m46s
CI / tests-integration (push) Successful in 2m33s
CI / tests-unit (push) Successful in 3m24s
CI / preflight (push) Skipped
CI / tests-quality (push) Successful in 1m31s
CI / tests-ui (push) Successful in 5m52s
CI / deploy (push) Successful in 3m27s
Adds the header.* keys introduced by the header rewrite (enter, search users, staff, mod/admin panel, command center, logs, logo generator, dashboard/profile/settings links, credits/duckets/diamonds, ...) to all 25 message files. Values are translated where available and fall back to English otherwise. The working tree files had been re-serialized with escaped unicode (\uXXXX); this commit restores literal UTF-8 so the diff shows only the content change instead of a full-file rewrite. |
||
|
|
c15177a52e |
fix(build): keep the server logger out of client bundles
CI / check (push) Successful in 33s
CI / tests-imaging-browsers (push) Successful in 1m50s
CI / tests-integration (push) Successful in 2m28s
CI / tests-unit (push) Successful in 3m6s
CI / tests-quality (push) Successful in 1m40s
CI / tests-ui (push) Successful in 5m56s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 3m58s
The production webpack build failed with UnhandledSchemeError: client components imported @/lib/logger, which binds pino, AsyncLocalStorage (node:async_hooks), node:crypto and node:fs — and validates server env on import. The UI fixture aliased those modules, so the harness and tests never hit it. - add src/lib/browser-log.ts: browser-safe logger with the same interface; errors are forwarded to /api/diagnostics/errors via reportBrowserError - guard src/lib/logger.ts with server-only and drop its now-dead browser branches - switch the 11 client components/hooks to @/lib/browser-log Verified with the Dockerfile's production build (pnpm run build) and the full vitest suite. |
||
|
|
fb470123c3 |
test(ui): stabilize cross-browser suite
CI / check (push) Successful in 30s
CI / tests-integration (push) Successful in 1m58s
CI / tests-imaging-browsers (push) Successful in 2m2s
CI / tests-unit (push) Successful in 2m9s
CI / tests-quality (push) Successful in 1m2s
CI / tests-ui (push) Successful in 4m50s
CI / preflight (push) Skipped
CI / deploy (push) Failing after 1m42s
- Run visual snapshots on Chromium only; Firefox/WebKit rendering does
not match Chromium pixel output. Functional and accessibility
assertions still run on all four projects (baselines were renamed to
the new project names in the previous commit).
- Poll axe audits until clean: WebKit can report stale color-contrast
violations for a moment after interactions while styles settle.
- Poll the Tab-focus assertion: Firefox can swallow a Tab while the
sandboxed srcdoc preview frame is still loading.
- Fix the recovery clock race: install the fake clock before navigation
at a fixed time and pause at a fixed target instead of wall-clock
values, which under load could already be in the fake clock's past
('Cannot fast-forward to the past').
|
||
|
|
1dd584cd82 |
fix(ui): make fixture bundle browser-safe, fast and cacheable
The UI fixture bundle crashed at runtime, so every test waited out its 45s timeout: - server-only modules leaked into the bundle and referenced node built-ins, the process global, and validated env at import time - the previous platform: 'node' fix kept esbuild happy but emitted require() calls that cannot run in the browser Fix it at the bundle boundary: - alias node:* imports to e2e/ui/node-stubs.mjs (shape-compatible stubs, no real I/O) - inject e2e/ui/process-shim.mjs for the process global - define process.env.SKIP_ENV_VALIDATION=1 so src/env.ts skips parsing in the fixture (same escape hatch vitest uses) Also make the fixture server fast to start: - build JS and Tailwind CSS in parallel - cache built assets in node_modules/.cache/nexst-ui-fixture keyed on a content hash of src/, fixtures, stubs and the server file - startup drops from ~1.7s to ~220ms on cache hits |
||
|
|
c9b363d60d |
fix(ui): convert node stubs to plain JavaScript
CI / check (push) Successful in 28s
CI / tests-integration (push) Successful in 1m54s
CI / tests-unit (push) Successful in 2m1s
CI / tests-imaging-browsers (push) Successful in 1m39s
CI / tests-ui (push) Failing after 32s
CI / preflight (push) Skipped
CI / deploy (push) Skipped
CI / tests-quality (push) Successful in 48s
Biome flagged TypeScript syntax in the .mjs stub module. Remove type annotations and prefix the unused run() store parameter with underscore to satisfy lint rules. |
||
|
|
e870beb71c |
fix(ui): stub Node built-ins for fixture bundle
CI / check (push) Failing after 20s
CI / tests-unit (push) Skipped
CI / tests-integration (push) Skipped
CI / tests-imaging-browsers (push) Skipped
CI / tests-ui (push) Skipped
CI / tests-quality (push) Skipped
CI / preflight (push) Skipped
CI / deploy (push) Skipped
Replace platform: 'node' (incompatible with iife browser bundle) with explicit aliases for node:async_hooks, node:crypto, node:fs/promises, node:path pointing at e2e/ui/node-stubs.mjs. Provides shape-compatible exports so esbuild can bundle the UI fixture without failing on Node built-ins. Increase webServer timeout to 120s for reliable startup. |
||
|
|
728999b2de |
feat(ui): multi-browser coverage for Playwright UI tests
CI / check (push) Successful in 28s
CI / tests-unit (push) Successful in 1m32s
CI / tests-integration (push) Successful in 1m37s
CI / tests-imaging-browsers (push) Successful in 2m20s
CI / preflight (push) Skipped
CI / tests-quality (push) Successful in 54s
CI / tests-ui (push) Failing after 16m47s
CI / deploy (push) Skipped
Add firefox and webkit projects alongside chromium (desktop/mobile), and enable reuseExistingServer so the fixture server isn't restarted per run. Chromium/Firefox/WebKit browsers installed via npx playwright install. |
||
|
|
8d8dab5817 |
fix(ui): esbuild platform node for UI fixture bundling
CI / check (push) Successful in 29s
CI / tests-imaging-browsers (push) Successful in 1m44s
CI / tests-integration (push) Successful in 1m49s
CI / tests-unit (push) Successful in 1m53s
CI / preflight (push) Skipped
CI / tests-quality (push) Successful in 45s
CI / tests-ui (push) Failing after 4m11s
CI / deploy (push) Skipped
Add platform: 'node' to esbuild build options so Node.js built-ins (node:async_hooks, node:crypto, node:fs/promises, node:path) are treated as external instead of failing to resolve during browser bundle generation in e2e/ui/fixture-server.mjs. |
||
|
|
59a45d2165 |
refactor: universal logger and remove N+1 catalog queries
CI / check (push) Successful in 28s
CI / tests-unit (push) Successful in 1m43s
CI / tests-integration (push) Successful in 1m50s
CI / preflight (push) Skipped
CI / tests-imaging-browsers (push) Successful in 1m56s
CI / tests-ui (push) Failing after 32s
CI / tests-quality (push) Successful in 1m14s
CI / deploy (push) Skipped
- Replace all 39 console.* calls with universal logger (pino server, console browser) - Set server-only marker on import-badge.ts - Disable DB query logging in production - Add bulkInsertCatalogItems: one transaction instead of N per-item inserts - Add reserveCatalogItemIds helper for bulk ID allocation - Optimize translateCatalogItems: single inArray batch query instead of N per-item selects - Test mock updated for logger.debug - biome clean, tsc clean, 3569 tests passing |
||
|
|
6895eaab49 |
style(test): use literal header access
CI / check (push) Successful in 31s
CI / tests-imaging-browsers (push) Successful in 1m30s
CI / tests-integration (push) Successful in 1m52s
CI / tests-unit (push) Successful in 1m58s
CI / preflight (push) Skipped
CI / tests-quality (push) Successful in 49s
CI / tests-ui (push) Successful in 2m38s
CI / deploy (push) Successful in 3m25s
|
||
|
|
8557370d91 |
chore(renovate): format schedule array
CI / check (push) Successful in 31s
CI / tests-integration (push) Successful in 1m57s
CI / tests-imaging-browsers (push) Successful in 1m21s
CI / tests-unit (push) Successful in 2m10s
CI / preflight (push) Skipped
CI / tests-quality (push) Successful in 1m0s
CI / tests-ui (push) Successful in 3m34s
CI / deploy (push) Successful in 3m32s
|
||
|
|
16a902bf14 |
fix(renovate): correct onboarding env value
CI / check (push) Failing after 22s
CI / tests-unit (push) Skipped
CI / tests-integration (push) Skipped
CI / tests-imaging-browsers (push) Skipped
CI / preflight (push) Skipped
CI / tests-ui (push) Skipped
CI / tests-quality (push) Skipped
CI / deploy (push) Skipped
|
||
|
|
dc4cca653b |
fix(renovate): correct workflow indentation
CI / check (push) Failing after 24s
CI / tests-unit (push) Skipped
CI / tests-integration (push) Skipped
CI / tests-imaging-browsers (push) Skipped
CI / tests-ui (push) Skipped
CI / tests-quality (push) Skipped
CI / preflight (push) Skipped
CI / deploy (push) Skipped
|
||
|
|
9894240f06 |
chore(renovate): align schedule and add onboarding guardrails
CI / check (push) Failing after 22s
CI / tests-unit (push) Skipped
CI / tests-integration (push) Skipped
CI / tests-imaging-browsers (push) Skipped
CI / preflight (push) Skipped
renovate.yaml (push) Invalid workflow file
CI / tests-ui (push) Skipped
CI / tests-quality (push) Skipped
CI / deploy (push) Skipped
|
||
|
|
43590f1509 |
feat(renovate): add OSV security alerts and pin the automerge strategy
CI / check (push) Successful in 31s
CI / tests-imaging-browsers (push) Successful in 1m31s
CI / tests-integration (push) Successful in 1m57s
CI / tests-unit (push) Successful in 2m3s
CI / preflight (push) Skipped
CI / tests-quality (push) Successful in 56s
CI / tests-ui (push) Successful in 2m48s
CI / deploy (push) Successful in 3m34s
Enable osvVulnerabilityAlerts (Gitea has no advisory feed of its own) with the OSV summary on the dependency dashboard, and let security fixes skip the 3-day minimumReleaseAge in their own labelled PR. Set automergeStrategy to squash so automerged dependency updates match the repository history. |
||
|
|
b58f3215f7 |
fix(renovate): keep Node.js and pnpm upgrades out of the bot
CI / check (push) Successful in 33s
CI / tests-imaging-browsers (push) Successful in 1m24s
CI / tests-integration (push) Successful in 2m0s
CI / tests-unit (push) Successful in 2m18s
CI / tests-quality (push) Successful in 1m5s
CI / tests-ui (push) Successful in 2m57s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 3m31s
Renovate bumped .nvmrc and the packageManager pin in isolation, so the check-node-toolchain contract failed (engines.node, @types/node and the Docker node image are intentionally upgraded together) and the grouped PR could never pass check. Disable the nvm manager, the Dockerfile node image and the pnpm packageManager field so those rollouts stay manual and coordinated. |
||
|
|
3a296551f6 |
fix(perf): enforce route budgets and ratchet coverage thresholds
CI / check (push) Successful in 31s
CI / tests-integration (push) Successful in 2m4s
CI / tests-unit (push) Successful in 2m16s
CI / tests-imaging-browsers (push) Successful in 1m30s
CI / preflight (push) Skipped
CI / tests-quality (push) Successful in 54s
CI / tests-ui (push) Successful in 3m1s
CI / deploy (push) Successful in 3m24s
Allow mode: enforce in the report config, fail the command on over-budget and unavailable routes, and make the markdown wording follow the configured mode. Recalibrate the budgets against the webpack build (baseline x1.15, rounded up to the next 10 KiB) now that the old Turbopack numbers no longer apply, so the Docker image build gate blocks genuine bundle regressions instead of only warning. Raise the Vitest coverage thresholds to the measured floor (37.17/30.1/31.79/38.17 -> 36/29/30/37). |
||
|
|
e70b96e3a7 |
feat(renovate): add self-hosted Renovate config and Gitea Actions workflow
Run the pinned renovate/renovate image on the host runner every weekday at 04:17 (plus workflow_dispatch) against the gitea platform, authenticating with the renovate-bot RENOVATE_TOKEN Actions secret. Minor and patch updates are grouped and automerged only after CI passes; majors wait for dashboard approval. Document the bot, secret rotation and the minimumReleaseAge policy in the error-centre runbook. |
||
|
|
480343d5a5 |
test(imaging): retry transient edge failures instead of flaking the suite
CI / check (push) Successful in 37s
CI / tests-integration (push) Successful in 2m3s
CI / tests-unit (push) Successful in 2m8s
CI / tests-imaging-browsers (push) Successful in 2m15s
CI / preflight (push) Skipped
CI / tests-ui (push) Successful in 2m54s
CI / tests-quality (push) Successful in 1m14s
CI / deploy (push) Successful in 3m37s
The cross-browser imaging job runs against the public origin, so every request goes through Cloudflare. One chromium run of "rejects malformed figures › missing figure" came back 525 (Cloudflare: TLS handshake to the origin failed) after a 40s stall — the request never reached the CMS, so a 400 was impossible to observe and the assertion was effectively testing the network. It passed on both firefox and webkit, which is the signature of an edge hiccup rather than a regression. `e2e/imaging/imaging-target.ts` now owns `getThroughEdge` / `fetchThroughEdge`, which retry on the statuses that mean "the app was never reached" (502/503/504 plus Cloudflare's 520-527) with a short backoff, and both edge-fronted specs use them. A genuinely broken edge still exhausts the retries and fails the run, so nothing is masked. Verified: 84 passed / 21 skipped / 0 failed against epicnabbo.nl with IMAGING_EDGE=1 across chromium, firefox and webkit. |
||
|
|
77a0d1010c |
feat(catalog-sync): report sources that can only be compared, not imported
CI / check (push) Successful in 47s
CI / tests-integration (push) Successful in 2m36s
CI / tests-unit (push) Successful in 2m52s
CI / preflight (push) Skipped
CI / tests-imaging-browsers (push) Successful in 2m47s
CI / tests-ui (push) Successful in 3m28s
CI / tests-quality (push) Successful in 1m30s
CI / deploy (push) Successful in 3m21s
The Habbo presets (and the other furnidata-only sources) carry no
`nitroBaseUrl`, so the clone importer's `${nitroBaseUrl}/${classname}.nitro`
download can never work against them — an `--import-new` run would have failed
for every single item instead of saying why. The SWF path that does work against
`images.habbo.com` lives in `furni-import.ts`, not in the clone importer this
CLI uses.
`stepImportNew` now skips those sources up-front, lists them under
"compared only" in the summary, and the menu prints the same warning when an
import step is chosen with such a source, pointing at the sources that do serve
bundles. Verified: Habbo (COM) reports compare-only, while Habboon and
VirtualCity list real candidates.
|
||
|
|
f56b345598 |
feat(catalog-sync): add import, reconcile, sprite-id and offer steps
CI / check (push) Successful in 37s
CI / tests-unit (push) Successful in 2m3s
CI / tests-integration (push) Successful in 2m54s
CI / tests-imaging-browsers (push) Failing after 3m23s
CI / tests-ui (push) Successful in 2m52s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 3m3s
CI / tests-quality (push) Successful in 6m8s
The CLI could audit and repair what already existed, but adding furniture present at a source was still only possible from the admin UI item by item. The repo already ships every piece of that pipeline, so wire them together as further steps of the same run: - `--import-new` imports furniture the compared source has and this hotel lacks. It reuses `getClonableClassnames` for the diff and `cloneSingleFurni` per item, which downloads the icon and the bundle (sources serve `.nitro`, stored as `.hab`), appends the furnidata entry with `deferFurniData` and creates the catalog page plus the offer itself. Deferred entries are written in one `appendFurniEntriesBulk` call, so 26000 items cost one JSON write, not one per item. `--only`, `--limit` and `--concurrency` narrow/tune it, failures are isolated per item and never abort the run. - `--reconcile`, `--fix-sprite-ids` and `--rebuild-offers` run the existing `reconcileFurniDataWithItemsBase`, `verifyAndFixSpriteIds` and `rebuildCatalogOfferIds` passes — the post-import consistency work. - `--align-ids` and `--rename-bundles` delegate to the existing standalone scripts; both only report until `--apply` is given, matching their own contracts. - The menu grows options 6-8 plus a dry run, each with its own confirmation. `--everything` turns on every repair + import step but deliberately leaves the destructive ones off. A live dry run against Wibbo listed 26593 items on the source that this hotel does not have, and Habbo (COM) reported 2871. |
||
|
|
a4bcd40e7b |
docs(catalog-sync): surface the bundle extension and the page-writing nuance
CI / check (push) Successful in 34s
CI / tests-integration (push) Successful in 2m1s
CI / tests-imaging-browsers (push) Successful in 2m5s
CI / tests-unit (push) Successful in 2m11s
CI / tests-ui (push) Successful in 2m46s
CI / preflight (push) Skipped
CI / tests-quality (push) Successful in 1m4s
CI / deploy (push) Successful in 3m48s
`.hab` has been the stored bundle extension since the `FURNI_BUNDLE_EXT` switch, so the repair path already writes `.hab` (the sources serve `.nitro`), but nothing in the output said so. Print the resolved extension in the run header and correct the header comment: generating the catalog SQL also creates the `catalog_pages` sub-pages it references, so a "generate only" run is not entirely read-only — only the `catalog_items` rows wait for `--apply-sql`. |
||
|
|
4b575d3a1d |
feat(catalog): add scripts/catalog-sync.ts CLI + interactive menu
CI / check (push) Successful in 32s
CI / tests-integration (push) Successful in 1m55s
CI / tests-unit (push) Successful in 2m1s
CI / tests-imaging-browsers (push) Successful in 2m7s
CI / preflight (push) Skipped
CI / tests-ui (push) Successful in 2m44s
CI / tests-quality (push) Successful in 1m46s
CI / deploy (push) Successful in 3m28s
Updating the catalog was only possible from the admin "Catalog audit" page, which streams `runCatalogAudit` over SSE and always compares against every enabled clone source. This adds the same engine to the terminal so it can be run by hand or from cron: - `scripts/catalog-sync.ts` — CLI driver around `runCatalogAudit`. Prints the live progress, the per-source "on the source but not in this hotel" counts and a summary block; generated catalog SQL is saved to `storage/catalog-sync/*.sql` (gitignored). Supports `--list-sources`, `--sources=<a,b>`, `--icons`, `--nitros`, `--furnidata`, `--structure`, `--check-ids`, `--sql`, `--apply-sql`, `--organize-sql`, `--all`, `--json` and `--fail-on-errors`. - `scripts/catalog-sync.sh` — interactive menu (`pnpm catalog:sync`). Lists the configured sources (so the menu always matches `clone_sources`), lets Habbo (COM) be taken with Enter, and offers audit-only through full repair + applying the catalog SQL, each with a distinct confirmation. With no arguments it needs a terminal; with any flag it passes straight through to the CLI. - `runCatalogAudit` gains `sourceIds` to restrict which sites are compared; omitting it keeps the previous "compare against everything enabled" behaviour. An audit writes nothing, and `--apply-sql` is the only flag that changes the catalog. Verified against the live DB: 16370 items_base rows, 16479 catalog items, 2871 Habbo (COM) entries missing from this hotel. |
||
|
|
61107848f8 |
fix(imaging): normalise avatar figures before building URLs
CI / check (push) Successful in 39s
CI / tests-integration (push) Successful in 2m2s
CI / tests-unit (push) Successful in 2m7s
CI / preflight (push) Skipped
CI / tests-imaging-browsers (push) Successful in 3m9s
CI / tests-ui (push) Successful in 2m46s
CI / tests-quality (push) Successful in 1m24s
CI / deploy (push) Successful in 4m9s
Legacy accounts can carry a malformed stored look — the old register default `hr-100-.hd-180-1...` has an empty colour slot — which the imager rejects with 400 "Invalid figure format", so the avatar renders broken everywhere the look appears. Normalise the figure in the shared URL builder (`getAvatarUrl`, used by every avatar on the site): an unrenderable look becomes `DEFAULT_AVATAR_FIGURE` while the proxy route keeps rejecting malformed input with 400. The rule set and default now live in one client-safe module (`src/lib/avatar-figure.ts`), shared by the URL builder and the server parser. |
||
|
|
1e3406a7ae |
fix(furni): keep classname env read out of the browser bundle
CI / check (push) Successful in 30s
CI / tests-unit (push) Successful in 2m0s
CI / tests-imaging-browsers (push) Successful in 2m0s
CI / tests-integration (push) Successful in 2m6s
CI / preflight (push) Skipped
CI / tests-ui (push) Successful in 2m41s
CI / tests-quality (push) Successful in 45s
CI / deploy (push) Successful in 4m11s
`src/lib/furni/classname.ts` is imported by client components for its pure string helpers, but it read `process.env.FURNI_BUNDLE_EXT` at module load. In any client bundle without a `process` shim — including the UI fixture's esbuild build — that threw `ReferenceError: process is not defined`, so the lazily-loaded organize-imports dialog never mounted and `pnpm test:ui` failed (studio.spec.ts). Fall back to the default extension when `process` is absent; server behaviour is unchanged. |
||
|
|
ef6c671903 |
test(ci): deterministic deploy gate + advisory quality suite; sync README versions
CI / check (push) Successful in 32s
CI / tests-imaging-browsers (push) Successful in 1m34s
CI / tests-integration (push) Successful in 1m59s
CI / tests-unit (push) Successful in 2m2s
CI / tests-quality (push) Successful in 1m1s
CI / tests-ui (push) Failing after 3m20s
CI / preflight (push) Skipped
CI / deploy (push) Skipped
The deploy gate ran e2e specs that depend on live content and data, so a missing upload (the /help article images) or a legacy malformed avatar figure could turn a safe code deploy red. Split the suites by what they actually guarantee: - Blocking gate (`pnpm test:e2e`, `playwright.config.ts`): only checks the CMS can guarantee itself — anonymous redirects, register form fields, the captcha DOM contract and the cache-control headers (deterministic origin-direct). - Advisory suite (`pnpm test:e2e:quality`, `playwright.quality.config.ts`): broken images, layout overflow and warm-page latency, which depend on live content/upload state and the host. It runs as a `continue-on-error` CI job against the public site so a real content problem stays visible without blocking the pipeline. Also add `scripts/sync-readme-versions.mjs` (+ tests, docs and a CI check) so the pinned versions in README.md can never drift from package.json / .nvmrc. |