Commit Graph
171 Commits
Author SHA1 Message Date
openhands 388d8992f8 feat: add CSV/JSON export, advanced bulk filters & selection to Catalog Manager
CI / check (push) Failing after 1m1s
CI / deploy (push) Skipped
CI / publish-container (push) Skipped
- Admin Audit Log: CSV/JSON export via ?format=query param
- Catalog Manager: club_only / have_offer filters (multi-filter support)
- Offer discovery: refactored discoverOffers() to accept filters object
- Translations added for new filter labels
- Test updates for all modified paths
2026-09-12 20:40:33 +02:00
openhands 4d720ee03c fix(furni): generate scale 32 from bundles with .png frame keys
CI / check (push) Successful in 2m30s
CI / deploy (push) Successful in 1m25s
CI / publish-container (push) Successful in 48s
resolveNitroFrame now matches spritesheet frame keys that carry a .png
suffix or namespaced naming, and isScale/scaleName preserve that suffix.
Broken source sprites (missing frames or references to icon artwork) are
skipped and reported instead of aborting the whole generation, and the
studio UI surfaces the skipped count.
2026-09-12 12:46:17 +02:00
openhands 683fee3bd9 fix: resolve layout type errors in organize-imports-dialog
CI / check (push) Successful in 2m29s
CI / deploy (push) Successful in 18s
CI / publish-container (push) Successful in 1m32s
2026-09-11 23:25:53 +02:00
openhands 61c7519bea fix(studio): show all offers in the imported-furniture tree
CI / check (push) Successful in 2m23s
CI / deploy (push) Successful in 1m11s
CI / publish-container (push) Successful in 44s
The organize-imports route defaulted to a 500-item limit, silently
hiding offers beyond the first batch of imported pages.  Remove the
effective cap (limit now means 'all', guarded only by a 50k lint cap)
so every offer already sitting in the import tree is returned and
grouped.
2026-09-11 20:33:27 +02:00
openhands 19dc0347df fix(studio): harden organize-imports against long-running queries and hangs
CI / check (push) Successful in 2m33s
CI / deploy (push) Successful in 1m26s
CI / publish-container (push) Successful in 50s
The original GET route used a correlated NOT EXISTS / FIND_IN_SET
subquery over the entire catalog_items table for every recent import
audit entry, causing server timeouts when the audit log or catalog
grew large.  The per-item host-page validation inside the create
action also issued one SELECT + one UPDATE per moved offer.

Changes:
- GET /api/admin/import/organize: replace the correlated subquery
  with a bounded candidate list and a JS-side placed-set check, then
  resolve all needed base items in a single indexed SELECT.  This
  bounds the query cost regardless of catalog or audit log size.
- organizeImportFurni action: validate mover ids in one SELECT, then
  batch every move per group into a single UPDATE with a CASE
  expression instead of one UPDATE per item.
- OrganizeImportsDialog: add a 45-second abort timeout on the fetch
  and a distinct load-error state so the UI never silently hangs.
- Add 'loadError' translation key (en + nl).
2026-09-11 20:24:38 +02:00
openhands 01a85ebcd0 feat(studio): add organize-imports tool with suggestion review and approval
CI / check (push) Successful in 2m22s
CI / deploy (push) Successful in 1m34s
CI / publish-container (push) Successful in 46s
Adds a Studio 'Organize imports' dialog that groups recently imported
furniture and furniture already sitting in the auto-created import
pages into suggested catalog categories.  Each group is presented with
its suggested name, icon, and layout which can be overridden before
approval; approved groups are turned into real catalog pages in a
single atomic export run.  Offers already inside the import subtree are
moved to the new pages; brand-new furniture gets a fresh offer.

- groupSuggestedCategories: generic pure helper reusing the same
  per-item label heuristic that drives suggestCategoryName; items with
  no label land in a 'Other Furni' remainder bucket
- GET /api/admin/import/organize: returns items from the imported
  furniture tree (catalog_items JOIN items_base via page id set from
  the imported-furniture root) union audit-logged but not-yet-placed
  recent imports; marks alreadyPlaced vs new
- organizeImportFurni server action: validates import-page membership
  before moving any offer, creates pages + inserts/moves items in one
  withCatalogExport snapshot, logs activity
- OrganizeImportsDialog: full-featured Studio dialog with price panel
  (applies to new offers only), parent select, per-group approval,
  editable name/icon/layout with suggestion reset chips, source tags
- import-pages.ts server helper: locates the imported-furniture tree
- Studio nav: 'Organize imports' button with FolderTree icon,
  gated on CATALOG_EDIT, wired next to the catalog manager
- en + nl translations for organizeImports.* keys with ICU plurals
- groupSuggestedCategories unit tests (deterministic grouping,
  remainder handling, size+alpha ordering, label consistency)
2026-09-11 19:38:18 +02:00
openhands f832479e52 feat(catalog): add auto-category wizard with live preview and smart suggestions
CI / check (push) Successful in 3m1s
CI / deploy (push) Successful in 2m7s
CI / publish-container (push) Successful in 45s
- Add AutoCategoryDialog: pick furni (or empty page), suggest caption/icon/layout, live preview
- Add createAutoCategory server action (page + offers in one export) with CatalogKind
- Extend furni search API with interactionType
- Share ShopTile and refactor inline-editor/items-shop-preview to use it
- Add suggestion heuristics (suggestCategoryName/dIcon/layout) with tests
- Add autoCategory translations (en/nl)
2026-09-11 18:47:31 +02:00
Simo 88790d1a0d feat(cms): recover drafts and failed imports with verified UI workflows
CI / check (push) Successful in 2m3s
CI / deploy (push) Successful in 1m31s
CI / publish-container (push) Successful in 1m41s
2026-09-11 08:58:10 +02:00
Simo 76f0420d64 feat(import): run catalog synchronizations as durable jobs
CI / check (push) Successful in 57s
CI / deploy (push) Successful in 18s
CI / publish-container (push) Successful in 1m18s
2026-09-11 00:36:22 +02:00
openhands 3e69b72513 feat(catalog): prevent and repair Arcturus emulator data errors
CI / check (push) Failing after 26s
CI / deploy (push) Skipped
CI / publish-container (push) Skipped
Block invalid catalog_items writes at the API level (points currency
allowlist, non-negative prices, positive amount, limited stack >= sold
count, unique sibling order numbers) and auto-assign unique order numbers
on bulk create. Add a catalog-maintenance scan + transactional repair that
fixes pre-existing rows: resets unsupported points_type, clamps negative
costs, sets amount to 1, raises limited_stack, renumbers duplicate orders
and deletes offers with missing page/item references. Surface the issue
count and a fix button in the admin maintenance panel.

Also: add enabled/retired flag to clone sources, classify poster and
currency furniture in item-kind, and remove the obsolete update-Nitrov3.sh.
2026-09-10 11:29:28 +02:00
Simo 1ef405be0a feat(cms): add recovery history and operational reliability tools
CI / check (push) Failing after 22s
CI / deploy (push) Skipped
CI / publish-container (push) Skipped
2026-09-09 21:57:56 +02:00
Simo 89526af344 feat(hk): expand search and add operational user overview
CI / check (push) Successful in 54s
CI / deploy (push) Successful in 1m16s
CI / publish-container (push) Successful in 1m57s
2026-09-09 21:14:10 +02:00
Simo c389c3893d feat(cms): improve catalog, editorial recovery and operations
CI / check (push) Successful in 52s
CI / deploy (push) Successful in 2m10s
CI / publish-container (push) Failing after 1m18s
2026-09-09 19:36:15 +02:00
Simo c4496e710b feat(docker): prepare portable images with runtime hotel configuration
CI / check (push) Successful in 1m6s
CI / deploy (push) Successful in 1m23s
2026-09-07 22:37:53 +02:00
Simo cbaa115d56 fix(deploy): verify Docker clone updates against the served release
CI / check (push) Successful in 59s
CI / deploy (push) Failing after 1m21s
2026-09-07 21:17:34 +02:00
Simo 193b6686a9 refactor(catalog): unify commands and embed guarded catalog workspace
CI / check (push) Successful in 1m16s
CI / deploy (push) Successful in 28s
2026-09-06 19:40:52 +02:00
Simo 9b0ea2fb16 fix(news): restore publication flow and deduplicate dashboard friends
CI / check (push) Successful in 1m6s
CI / deploy (push) Successful in 59s
2026-09-06 18:32:43 +02:00
Simo a070004e7b feat(admin): reorganize housekeeping and strengthen shared workflows
CI / check (push) Successful in 1m5s
CI / deploy (push) Successful in 1m4s
2026-09-06 17:17:30 +02:00
openhands 9dc9d1fa4b perf: pre-compress gamedata JSON, tune MariaDB, fix avatar imager, docs
CI / check (push) Successful in 1m3s
CI / deploy (push) Successful in 1m12s
- scripts/compress-gamedata.mjs: pre-compress large gamedata JSON to .gz
  (gzip level 9, idempotent mtime check) served via nginx gzip_static
  (48 MB FurnitureData.json -> ~2.4 MB, ~0.3s -> ~0.005s per request)
- package.json: add gamedata:compress script
- fix(imaging): accept real Habbo figure strings in avatar route
  (allow optional second number per part, e.g. hd-180-1.ch-210-66)
- README: document avatar imager container (avatar-imaging-pixinode,
  port 8082, /docker/Polaris-imager), nginx /imaging proxying, MariaDB
  tuning, gamedata pre-compression cron and caching layers
2026-09-06 12:06:38 +02:00
openhands 8c12fc6c60 refactor(cms): deduplicate shared admin components and fix studio batch completion
CI / check (push) Failing after 1m35s
CI / deploy (push) Skipped
CI / e2e (push) Skipped
- fix(studio): stop markBatchDone infinite recursion so batches complete
- refactor(api): merge api-response into api and drop the duplicate module
- refactor(media): extract shared media loader and URL validator
- refactor(ui): extract shared LoadingSpinner for site and admin groups
- refactor(dates): consolidate raw date formatting into formatDate util
- refactor(logs): share a single generic log-list loader across tables
- refactor(theme): merge both ColorField components and reuse contrast helpers
- refactor(import): extract shared ImportErrorBanner and SearchInput
- chore(): remove dead theme-editor-tabs after inlining tab components
2026-09-05 20:58:42 +02:00
Simo 816e3875c2 feat(admin): add production error center and refresh CMS dependencies 2026-09-05 19:53:09 +02:00
Simo 570f3dde44 feat(catalog): repair missing furniture components with verified status
CI / check (push) Successful in 1m33s
CI / deploy (push) Successful in 1m22s
CI / e2e (push) Successful in 24s
2026-09-05 18:12:34 +02:00
Simo cd75361b9f feat(catalog): generate derived scale 32 with preview and backup restore
CI / check (push) Successful in 1m32s
CI / deploy (push) Successful in 1m12s
CI / e2e (push) Successful in 21s
2026-09-05 17:36:22 +02:00
Simo 08b0b5021e feat(catalog): inspect Nitro scales and preview original sprites
CI / check (push) Successful in 1m47s
CI / deploy (push) Successful in 1m30s
CI / e2e (push) Successful in 22s
2026-09-05 17:22:27 +02:00
Simo 2619bec165 feat(catalog): queue furniture imports with history and matching file attachments
CI / check (push) Successful in 1m30s
CI / deploy (push) Successful in 1m26s
CI / e2e (push) Successful in 25s
2026-09-05 17:02:26 +02:00
Simo 33b6d1520e fix(catalog): stream single imports and preserve response errors
CI / check (push) Successful in 1m31s
CI / deploy (push) Successful in 1m13s
CI / e2e (push) Successful in 21s
2026-09-05 15:16:42 +02:00
Simo f0dcbee162 fix(ci): normalize source asset test formatting
CI / check (push) Successful in 1m30s
CI / deploy (push) Successful in 1m9s
CI / e2e (push) Successful in 21s
2026-09-05 15:07:26 +02:00
Simo 159b1f7d1b fix(catalog): check source assets and offer reachable import alternatives
CI / check (push) Failing after 19s
CI / deploy (push) Skipped
CI / e2e (push) Skipped
2026-09-05 14:56:04 +02:00
Simo 8a919f85b2 Preserve furniture revisions when downloading source assets
CI / check (push) Successful in 1m31s
CI / deploy (push) Successful in 1m21s
CI / e2e (push) Successful in 21s
2026-09-05 14:29:48 +02:00
Simo a78d8256e0 Recognize imported furniture by normalized classname and local IDs
CI / check (push) Successful in 1m30s
CI / deploy (push) Successful in 1m21s
CI / e2e (push) Successful in 22s
2026-09-05 14:04:52 +02:00
Simo 9f791ba284 Support Gitea configuration and safe Catalog Studio furniture completion
CI / check (push) Successful in 1m31s
CI / deploy (push) Successful in 1m18s
CI / e2e (push) Successful in 21s
2026-09-05 13:33:40 +02:00
Simo 26f071117b Add Catalog Studio inspection and guided import review
CI / check (push) Successful in 1m39s
CI / deploy (push) Successful in 1m18s
CI / e2e (push) Successful in 25s
2026-09-05 13:10:43 +02:00
Simo 9ec9ab31ad feat: export Catalog Studio assets and SQL to catalog repository
CI / check (pull_request) Failing after 1m21s
CI / deploy (pull_request) Skipped
CI / e2e (pull_request) Skipped
2026-09-05 11:49:00 +02:00
openhands 458972fdfd fix: improve batch import error handling and resilience
CI / check (push) Successful in 1m25s
CI / deploy (push) Successful in 1m57s
CI / e2e (push) Successful in 26s
- Add retries for furnidata fetch (3 attempts, 1s delay)
- Better error messages for user (distinguish 502/400/other)
- Client-side: show detailed error from SSE stream when available
- Remove unused admin-helpers.test.ts
2026-09-04 18:28:14 +02:00
openhands 399c047515 fix: harden admin actions, search, sanitization and repo hygiene
CI / check (push) Successful in 1m21s
CI / deploy (push) Successful in 1m25s
- Split approve/dismiss application workflows with distinct audit logs,
  rate-limited guards and real error logging
- Validate article status/date/id input and stop resetting publishedAt
  on every update
- Validate guild updates (state, forum enums, non-empty name) behind
  rate-limited guard
- Fix scheduled-article publishing (ignore NULL dates, set updatedAt,
  type-safe predicates)
- Harden admin search API (LIKE escaping, query cap, per-user
  rate limit, round-robin result cap) and fix search dialog
  abort/res.ok/loading races
- Lock down HTML sanitizer to an allowlist profile and add XSS tests
- Improve mobile nav accessibility (unique id, dialog role, focus
  management, scroll lock, outside close)
- Log swallowed server errors instead of silent catch blocks
- Remove dead eslint config, drop unused dompurify deps, restore knip
  CI step, add Playwright config with smoke spec
2026-09-04 13:04:08 +02:00
openhands 30c95b1a5c feat: comprehensive CMS improvements
CI / runtime-diagnostics (push) Skipped
CI / release (push) Skipped
CI / check (push) Failing after 0s
CI / deploy (push) Skipped
- Fix DOMPurify SSR crash (use isomorphic-dompurify)
- Fix SanitizedHtml to sanitize by default
- Add auth guards to studio/catalog maintenance pages
- Add update/edit to vouchers CRUD
- Add update/edit to rare-values CRUD
- Add approve workflow to applications page
- Add edit form to guilds detail page
- Add SEO metadata to all public pages (21 pages)
- Fix mobile nav accessibility (focus trap, aria attributes)
- Fix missing labels and table accessibility
- Add dynamic imports for heavy client components (6 components)
- Fix silent error swallowing (40+ locations)
- Add content scheduling for articles (publishAt, status)
- Wire up 12 missing webhook notification triggers
- Add global search to admin panel
- Add bulk actions to admin users table
- Fix JSON formatting and a11y issues
2026-09-03 16:00:32 +02:00
openhands 67b67798b9 feat(client): polished toolbar, live online count via SSE
CI / runtime-diagnostics (push) Skipped
CI / check (push) Successful in 28s
CI / release (push) Skipped
CI / deploy (push) Successful in 1m27s
- Redesign in-game client toolbar with refined glass styling and buttons
- Live online count + emulator status streamed over SSE multicast
- Who's-online tooltip throttled to reduce repeated requests
- Fix show button so it always returns the hidden toolbar
- Use theme CSS variables instead of hardcoded colors
- Add toolbar translations across all 25 locales
2026-09-02 21:14:42 +02:00
openhands 52516a368d fix: skip heavy post-import consolidation on non-final clone chunks
CI / runtime-diagnostics (push) Skipped
CI / check (push) Successful in 38s
CI / release (push) Skipped
CI / deploy (push) Successful in 1m2s
The flush after every 400-item chunk was running expensive operations
(reconcileOfferIds, rebuildCatalog, verifySpriteIds, rcon updates) which
caused the import to hang after ~800 items. Now only the final chunk
triggers the full consolidation. Also raised the per-request limit from
500 to 5000 items.
2026-09-01 18:29:06 +02:00
openhands 1374bd332f Studio: add clone-all-per-hotel, per-item status detail, retry, ETA, and auto-translate
CI / runtime-diagnostics (push) Skipped
CI / check (push) Successful in 36s
CI / release (push) Skipped
CI / deploy (push) Successful in 1m14s
- Add 'Clone all missing' button for clone sources with confirmation dialog
- Show per-item status badges: nitro, furnidata, catalog entry
- Add status filters: missing furnidata, missing catalog entry
- Add ETA and percentage to batch progress bar
- Add retry button for failed items after batch import
- Auto-translate all languages after clone-all completes
- Fix statusFilter 'all' bug that incorrectly filtered imported items
- Bulk-load FurnitureData + catalog references for O(1) per-item checks
2026-09-01 17:29:12 +02:00
openhands 1dc8d1d46f feat: add official furnidata sync button for importing all missing items
CI / check (push) Successful in 29s
CI / release (push) Skipped
CI / deploy (push) Successful in 55s
- API endpoint: /api/admin/import/official/sync-all
  - Fetches all official Habbo furnidata
  - Compares with database to find missing items
  - Imports missing items via SSE batch with progress reporting
  - 500 item limit for safety
  - Proper abort signal support
- Client component: OfficialSyncClient with progress UI
- Updated StudioSyncPage to include Official Furnidata sync option
- Uses existing importSingleFurni infrastructure
2026-08-31 20:24:46 +02:00
openhands 7556b1f3fa perf: prevent import hanging with timeouts and batching
CI / check (push) Successful in 31s
CI / release (push) Skipped
CI / deploy (push) Successful in 1m1s
- verifyAndFixInteractionModesCount: paginated DB queries (500/batch)
  instead of loading all items into memory at once
- withFurniDataLock: add 60s chain timeout to prevent deadlocks
  when a lock holder stalls or crashes
- withGamedataLock: same timeout protection for gamedata locks
- conversion-pool: add 60s per-job timeout, fall back to main thread
- furni/batch: abort signal + post_import progress events + skip
  post-import steps when client disconnects
- furni/batch-regen: abort signal + early exit when disconnected
- clone/sync-all: pre-fetch furnidata once per source instead of
  per item (eliminates 2000+ redundant fetches)
- sse-client: add 60s idle timeout to prevent infinite hangs
2026-08-31 18:25:32 +02:00
openhands f70d96b81c fix: prevent import hanging by adding abort signals and idle timeouts
CI / check (push) Successful in 28s
CI / release (push) Skipped
CI / deploy (push) Successful in 59s
- Furni batch: wire request.signal to abort controller, send post_import
  progress events, skip post-import steps when aborted
- Clone sync-all: pre-fetch furnidata once per source instead of per item
  (eliminates 2000+ redundant DB reads + HTTP requests)
- SSE client: add 60s idle timeout to prevent infinite hangs when server
  stops responding
2026-08-31 18:11:54 +02:00
openhands a98b194386 feat: add scoped theme builder system with per-route, per-module, and multi-site support
- Add theme_scopes and theme_scope_values database tables for scoped themes
- Implement theme resolver engine with inheritance: global > site > module > route
- Add module detection for 20+ routes (shop, guilds, radio, news, etc.)
- Create admin UI at /admin/theme-builder with scope tree and color editor
- Add ScopedThemeVars component for injecting scoped CSS via data-attributes
- Add ThemeScopeDetector client component for runtime module/route detection
- Add site-resolver for multi-site domain detection
- Add /api/themes/export endpoint (JSON, CSS, variables formats)
- Add /api/themes/export/embed.js for external integration widget
- Add server actions for full CRUD on scopes and theme values
- Add admin nav link and EN/NL translations
2026-08-31 17:15:42 +02:00
Simo b1ddda66ff Revert "Merge pull request 'Complete Housekeeping migration and /ase cutover' (#52) from codex/housekeeping-complete into main"
CI / check (push) Successful in 27s
CI / release (push) Skipped
CI / deploy (push) Successful in 43s
This reverts commit 488b6e57c4, reversing
changes made to b506b4499a.
2026-08-30 21:31:34 +02:00
Simo 1ec05cda39 test: make media route fixture cross-platform
CI / check (pull_request) Successful in 34s
CI / release (pull_request) Skipped
CI / deploy (pull_request) Skipped
2026-08-30 12:27:12 +02:00
Simo c524b305d7 fix(housekeeping): address task 14 review round 2 2026-08-30 11:30:17 +02:00
Simo d09eaa33d6 fix(housekeeping): address task 14 review round 1 2026-08-30 10:53:50 +02:00
openhands 164a4f4ef6 refactor: remove hotel-name fallback, fail fast when unconfigured
CI / check (push) Failing after 39s
CI / release (push) Skipped
CI / deploy (push) Skipped
Drop the hardcoded FALLBACK_HOTEL_NAME ("Atom") preset and the brand.ts
module. HOTEL_NAME is now a required env var: if it (and the CMS hotel_name
setting) is missing the site fails validation at startup/build with a clear
message instead of silently rendering a placeholder hotel name.

resolveHotelName() resolves CMS hotel_name -> required HOTEL_NAME only.
Callers that used the preset (api/home route catch branch, CMS settings form
default, mobile-nav/logo-generator prop defaults) now use the configured name
or an empty default; the real name is already passed in by server parents.
2026-08-27 16:35:00 +02:00
openhands 6dced0fb54 feat: per-import translation toggle and language picker in studio
CI / check (push) Successful in 28s
CI / release (push) Skipped
CI / deploy (push) Successful in 53s
Furni imports can now choose whether to translate (per import) and which
languages to build, instead of always rebuilding all 13 FurnitureData_<lang>
files. The studio header also has a global switch that persists the
furnidata_translate_enabled setting, seeding the per-import default.
2026-08-24 18:16:42 +02:00
openhands c7ba04bda1 feat: relocate import tools into studio and harden catalog/furnidata integrity
CI / check (push) Failing after 26s
CI / release (push) Skipped
CI / deploy (push) Skipped
- Move /admin/import/* tools under /admin/studio/* and add studio nav, layout and tabs
- Add shared catalog maintenance panel plus a /admin/studio/maintenance tab
- Make furnidata reconciliation overwrite conflicting entries with the
  DB-authoritative items_base classname/id (surfaced via fixedConflicts)
- Add furnidata_translate_enabled setting to skip the heavy localized
  furnidata build during import (manual build-languages still forces it)
- Update staff smoke contract test for the studio hub
2026-08-24 17:13:03 +02:00