Feat/asset discovery ux - #68
Merged
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
This PR upgrades the asset discovery experience end-to-end: it introduces a more robust search/filter UX, adds derived fields + migrations to support “honest” sorting (rating score, normalized modify date), and hardens several security and operational behaviors (CSRF checks, URL sanitization, safer auth flows).
Changes:
- Reworked search request parsing, URL/state management, facets, and templates to support multi-facet filtering, pagination, and related-results UX.
- Added MongoDB migrations + maintenance scripts to backfill/search-index data and keep ratings consistent (Wilson score + dedupe).
- Added security hardening and UX/accessibility improvements across auth, routing, templates, and styles; introduced a Node
node:testtest suite.
Reviewed changes
Copilot reviewed 111 out of 113 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.test.json | Adds a dedicated TS config for compiling tests. |
| tests/search.test.ts | Tests search parsing, pagination, URL building, and view model behavior. |
| tests/safe-url.test.ts | Tests URL scheme validation utility. |
| tests/rating.test.ts | Tests Wilson score rating behavior. |
| tests/rating-summary.test.ts | Tests rating summary formatting and scoring. |
| tests/node-test.d.ts | Shim types for node:test for pinned Node typings. |
| tests/media.test.ts | Tests preview/media normalization behavior. |
| tests/card-view.test.ts | Tests card URL sanitization behavior. |
| tests/bootstrap.cjs | Registers TS path aliases for compiled test output. |
| tests/asset-url.test.ts | Tests canonical asset URL + “return to results” encoding. |
| src/core/utils/safeUrl.ts | Adds shared http(s)-only URL guard for untrusted content. |
| src/core/utils/ratingSummary.ts | Adds “approval percent + count” rating summary model. |
| src/core/utils/ratingScore.ts | Adds Wilson lower-bound scoring for “Highest rated” ranking. |
| src/core/utils/rateLimitHandler.ts | Adds shared rate-limit handler that can render HTML 429 pages. |
| src/core/utils/mediaHelpers.ts | Improves preview classification + blocks non-http(s) media links. |
| src/core/utils/httpError.ts | Introduces BadRequestError with explicit HTTP status support. |
| src/core/utils/escapeHtml.ts | Adds HTML-escaping helper for safe template interpolation. |
| src/core/utils/cardView.ts | Adds pre-render enrichment/sanitization for card models. |
| src/core/utils/assetUrl.ts | Adds canonical asset URL + return URL builders. |
| src/core/start.ts | Runs migrations during startup (best-effort). |
| src/core/RouterServer.ts | Adds CSRF origin/referer checks, no-store for account routes, better error/404 handling. |
| src/core/MongoHelper.ts | Tunes Mongo connection pool sizing/idle pruning via env vars. |
| src/core/modules/authentication/services/UserServices.ts | Adds dummy Argon2 verify to reduce username timing oracle. |
| src/core/modules/authentication/models/user/DELETE/DeleteResumeToken.ts | Adds logout-time resume token revocation. |
| src/core/modules/authentication/controllers/users/UserController.ts | Hardens auth cookies, stops returning raw tokens, makes logout POST + revocation. |
| src/core/migrations/runMigrations.ts | Adds CLI entrypoint to run migrations. |
| src/core/migrations/index.ts | Registers ordered, idempotent migrations. |
| src/core/migrations/0004-dedupe-reviews.ts | Dedupes reviews + creates unique compound index. |
| src/core/migrations/0003-backfill-modify-date.ts | Backfills normalized modify_date_at for stable sorting. |
| src/core/migrations/0002-backfill-rating-score.ts | Backfills derived rating_score for ranking. |
| src/core/migrations/0001-create-text-index.ts | Creates/verifies weighted MongoDB text index for search. |
| src/core/maintenance/runReconcileRatings.ts | CLI runner for ratings reconciliation. |
| src/core/maintenance/runCatalogAudit.ts | CLI runner for catalog audit. |
| src/core/maintenance/reconcileRatings.ts | Recomputes counters/score from canonical reviews. |
| src/core/maintenance/catalogAudit.ts | Adds read-only catalog health auditing. |
| src/core/ensureIndexes.ts | Adds new indexes and verifies required text index presence. |
| src/app/utilities/sitemapGenerator/jobs/generateSitemap.ts | Switches sitemap to https and excludes unavailable/non-searchable assets. |
| src/app/utilities/fetchReadme/services/FetchReadme.ts | Adds URL validation and readme fetch status tracking. |
| src/app/utilities/fetchReadme/models/UPDATE/UpdateAssetReadmeState.ts | Persists README fetch status/error fields on assets. |
| src/app/utilities/fetchFromGodot/schema/assets.ts | Extends asset schema with derived/source/readme status fields. |
| src/app/utilities/fetchFromGodot/jobs/fetchFromGodot.ts | Adds source-status tracking, version window iteration, and sync normalization. |
| src/app/components/utils/variables.scss | Introduces semantic design tokens and scales. |
| src/app/components/utils/mixins.scss | Adds rating typography helpers. |
| src/app/components/utils/forms.scss | Improves dropdown/logout form styles and adds validation/focus primitives. |
| src/app/components/utils/body.scss | Adds skip link, focus-visible rules, reduced-motion handling, and UI primitives. |
| src/app/components/partials/stars/stars.eta | Replaces “stars” with approval-percent + counts display. |
| src/app/components/partials/page-message/styles.scss | Converts page messages into toast-style notifications. |
| src/app/components/partials/page-message/page-message.eta | Adds ARIA live-region semantics for messages. |
| src/app/components/partials/page-banner/styles.scss | Adds back-link + breadcrumb styling. |
| src/app/components/partials/page-banner/page-banner.eta | Adds optional back-link + breadcrumbs; avoids unescaped title output. |
| src/app/components/partials/nav/styles.scss | Updates styles for mobile search button. |
| src/app/components/partials/nav/nav.eta | Switches search to GET, improves a11y, and changes logout to POST form. |
| src/app/components/partials/modal-report/modal-report.eta | Improves dialog semantics and fixes harassment spelling in UI. |
| src/app/components/partials/modal-media/modal-media.eta | Aligns media modal with shared dialog close attributes. |
| src/app/components/partials/modal-install/styles.scss | Refactors install modal into a clearer step-based UI. |
| src/app/components/partials/modal-install/modal-install.eta | Adds guided installation UX and safer external download behavior. |
| src/app/components/partials/modal-delete/modal-delete.eta | Improves delete modal dialog semantics. |
| src/app/components/partials/head/head.eta | Adds support for noindex meta on specific pages. |
| src/app/components/partials/footer/footer.eta | Makes copyright year dynamic. |
| src/app/components/partials/catalog-grid/styles.scss | Adds pagination/no-results styling enhancements. |
| src/app/components/partials/catalog-grid/asset-grd-schema.ts | Extends card schema with meta/context fields. |
| src/app/components/partials/asset-card/styles.scss | Adds meta row, CTA styling, and improved rating presentation. |
| src/app/components/partials/asset-card/asset-card.eta | Reworks card structure/CTA/rating output and supports “return to results”. |
| src/app/components/partials/asset-card-grid/results.eta | Adds a reusable results grid partial. |
| src/app/components/layouts/promobar-nav-body-footer/promobar-nav-body-footer.eta | Adds skip link and uses semantic <main> for content. |
| src/app/code/search/views/templates/search.eta | Rebuilds filters UI as a GET form with clear-section links and related assets section. |
| src/app/code/search/views/styles/styles.scss | Adds responsive filter toggles and related-results layout. |
| src/app/code/search/services/SearchService.ts | Switches to parsed request + view model, adds related assets and page clamping redirect. |
| src/app/code/search/services/parseSearchRequest.ts | Adds canonical parsing/normalization for query + filters + sort + pagination. |
| src/app/code/search/services/buildSearchViewModel.ts | Adds URL/state/view model builder for search UI. |
| src/app/code/search/models/GET/sortUtils.ts | Adds numeric-aware version comparison. |
| src/app/code/search/models/GET/GetSearchFacets.ts | Implements disjunctive (self-excluding) facet aggregations. |
| src/app/code/search/models/GET/GetAssetsFromQuery.ts | Adds deterministic sort keys, projections, and derived sort fields. |
| src/app/code/search/models/GET/GetAssetsCountFromQuery.ts | Updates counting to use new filter options and query timeouts. |
| src/app/code/search/models/GET/buildSearchFilter.ts | Extends search filters (types/support/featured) + $text support. |
| src/app/code/search/controllers/SearchController.ts | Uses shared rate-limit handler. |
| src/app/code/register/views/templates/register.eta | Adds better input types/autocomplete and correct submit buttons. |
| src/app/code/lost/views/templates/server-error.eta | Adds dedicated HTML error page template. |
| src/app/code/homepage/views/templates/index.eta | Updates homepage sections/CTAs and empty states. |
| src/app/code/homepage/views/styles/styles.scss | Adds section header styling, responsive grids, and chips/notes. |
| src/app/code/homepage/services/HomepageService.ts | Fetches sections concurrently, adds context line, and sanitizes card URLs. |
| src/app/code/homepage/models/GET/GetTrendingAssets.ts | Makes “popular” deterministic and rating_score-driven. |
| src/app/code/homepage/models/GET/GetLastModifiedAssets.ts | Increases results and sorts by normalized modify date. |
| src/app/code/homepage/models/GET/GetFeaturedAssetsForHomepage.ts | Makes featured assets deterministic and rating_score-driven. |
| src/app/code/homepage/controllers/HomepageController.ts | Uses shared rate-limit handler. |
| src/app/code/dashboard/views/templates/reviews.eta | Renames reviews section and uses a new review list component. |
| src/app/code/dashboard/views/templates/manage.eta | Adds safer account deletion flow (POST + confirmation + password). |
| src/app/code/dashboard/views/templates/dashboard.eta | Improves form a11y/required fields/autocomplete. |
| src/app/code/dashboard/views/templates/components/sidebar.eta | Adds aria-current semantics and passes view context. |
| src/app/code/dashboard/views/templates/components/review-list.eta | Adds a structured “Ratings & Reviews” list with pagination. |
| src/app/code/dashboard/views/styles/styles.scss | Styles new dashboard buttons, deletion form, and review list. |
| src/app/code/dashboard/models/GET/GetUserReviewsByToken.ts | Reads canonical reviews collection with paging/sorting. |
| src/app/code/dashboard/models/GET/GetUserAssetsFromQuery.ts | Expands projections for card rendering in dashboard views. |
| src/app/code/dashboard/models/DELETE/DeleteUserById.ts | Fixes deletion key and validates one-row delete. |
| src/app/code/dashboard/controllers/DashboardController.ts | Deprecates save toggle GET, adds POST saved endpoint, moves delete to POST. |
| src/app/code/asset/views/templates/quick-info.eta | Adds review anchor, safer external links, and clearer actions. |
| src/app/code/asset/views/styles/styles.scss | Improves review/media interactions, adds markdown styling, and new actions layout. |
| src/app/code/asset/services/AssetService.ts | Adds back-link validation, URL sanitization, review paging/count, related assets, and better error handling. |
| src/app/code/asset/models/UPDATE/RefreshAssetRating.ts | Recomputes counters + rating_score from canonical reviews. |
| src/app/code/asset/models/GET/GetRelatedAssets.ts | Adds related-asset selection with compatibility-aware tiers. |
| src/app/code/asset/models/GET/GetAssetReviewsById.ts | Adds deterministic review paging and ordering. |
| src/app/code/asset/models/GET/GetAssetReviewCount.ts | Adds review count helper. |
| src/app/code/asset/models/GET/GetAssetDisplayInformation.ts | Returns nullable asset display data instead of throwing. |
| src/app/code/asset/controllers/AssetController.ts | Uses shared rate-limit handler for rendering endpoint. |
| README.md | Updates verification/testing commands and migration guidance. |
| package.json | Adds typecheck, lint:check, migrations, maintenance, and test scripts. |
| .gitignore | Ignores compiled test output directory. |
| .eslintignore | Ignores compiled test output directory. |
| .env.example | Documents Mongo pool tuning and import window configuration. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 111 out of 113 changed files in this pull request and generated 1 comment.
Suppressed comments (4)
src/core/RouterServer.ts:188
- The global error handler decides to render HTML based on req.accepts(['html','json']). For fetch/XHR requests that send Accept: /, Express will pick 'html' (first match), so callers expecting JSON (e.g. utilities.js callRouteAjax uses response.json()) can break on error responses.
src/core/utils/rateLimitHandler.ts:12 - This 429 handler uses req.accepts(['html','json']) to decide between HTML and JSON. Requests with Accept: / (common for fetch without an explicit Accept header) will be treated as HTML, but callers like callRouteAjax expect JSON on failures.
src/app/components/partials/asset-card/asset-card.eta:39 - The Save/Unsave action in the card menu is an element that relies on JS. This creates a fake navigation target and loses button semantics (pressed state, keyboard behavior). Use a real like the asset page quick-info menu (and set aria-pressed).
src/app/code/asset/services/AssetService.ts:58 - When the asset id is missing, this throws a plain Error. With the updated RouterServer error handler, unmarked errors become 500 responses, but this is a client error and should be a 400 (BadRequestError).
if (assetId === '') {
throw new Error('Missing asset ID')
}
Comment on lines
8
to
+9
| <form action="POST" method=""> | ||
| <h2>Delete <span class="type">Comment</span></h2> | ||
| <h2 id="delete-dialog-title">Delete <span class="type">Comment</span></h2> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Goal:
Make the Godot Asset Library easier to browse, search, and explore. Rebuilds search with real filters/facets and honest rating sort, revamps asset cards, adds a related-assets row, restores a cleaner homepage and asset-page banner, adds a Ratings & Reviews dashboard page, and hardens the backend with migrations, review dedup, CSRF protection, and a fix for Mongo connection-pool exhaustion.
Testing Instructions
npm run typecheck && npm run lint:check && npm test(55/55 tests) andnpm run build.docker compose up -d --build nodejs(migrations auto-run at startup and skip if already applied)./search/?q=,/category/2d+tools): filter sidebar (Category/Godot Version/Asset Type/Support + Featured only) applies via "Apply filters"; Sort By / Results per Page are custom dropdowns; pagination with page numbers + Back/Next works; "You may also like" shows on single-result queries./dashboardsidebar links work;/dashboard/reviews/lists reviews.seq 1 40 | xargs -P 40 -I{} curl -s -o /dev/null http://localhost:8080/and checkdocker logs gda_nodejsfor "Timed out while checking out a connection".Resources
docs/asset-exploration-ux-plan.md(full plan + rationale)feat/asset-discovery-ux(test harness → search → cards → asset page → homepage → dashboard → auth → migrations → client JS → importer → docs)Checklist