Estimate: 50m · Depends on: 6.13.2
The search + category/tag narrowing over the 6.13.2 directory — the GitLab-Explore name-search + the GitHub-Topics / GitLab-Topics category filter. It NARROWS the same cursored directory read; it does NOT open a second query path.
- Search: a name/description contains-match over the public projects in the directory. Ride the SHIPPED 6.1.1 FilterAST / its safe parameterized compiler + the trgm text index where it fits (the contains-match over project name/description is exactly its shape); where the project-level directory search does not map onto the 6.1.1 work-item search, a SCOPED parameterized search (no string-built SQL — the 6.1.1 injection-safety posture) over the public-project set. The search composes with the active rank tab (6.13.4) + the cursor pagination, and is bounded (no load-all of the result).
- Category / tag filter: narrow the directory to a category/tag (the 6.13.5 tag model) — an EXISTS-over-the-tag-join predicate that composes with search + the rank under the cursor. (6.13.5 owns the tag model + the tag-facet read; this card consumes them as a filter predicate over the directory.) The tag filter + search are both parameterized, both respect the
access_level = public directory filter (you can only ever search/filter public projects).
Stay 4-layer: the route parses the query/tag params + calls ONE service method that threads the search/tag predicate into the 6.13.2 cursored read; the predicate compilation lives in the service/repository (no raw Prisma in the route); no user string reaches SQL unparameterized.
Acceptance criteria
- A name/description query narrows the directory to matching public projects; it rides the 6.1.1 FilterAST/compiler where it fits, else a scoped parameterized search — no string-built SQL on the path (injection-safe, the 6.1.1 posture).
- A category/tag selection narrows the directory to that topic (an EXISTS over the 6.13.5 tag join); search + tag + the rank tab COMPOSE under one cursored read.
- Both predicates respect the
access_level = public directory filter (no non-public project is ever searchable/filterable) and the cursor pagination (no load-all of the result set).
- 4-layer respected; no raw Prisma in the route; the search/filter compose with 6.13.2’s deterministic order + cursor.
Context refs
- 6.13.2 (the cursored directory read this narrows) + 6.13.5 (the tag model the category filter consumes) + 6.13.4 (the rank the search composes with).
scripts/plan-seed/data/story-6.1.ts § 6.1.1 (the SHIPPED FilterAST + the safe parameterized compiler + the trgm text index this rides where it fits) — lib/filters/ast.ts / lib/filters/registry.ts.
- GitLab Explore name search + Topic filter (https://gitlab.com/explore/projects/trending, https://docs.gitlab.com/user/project/project_topics/) — the search + category browse mirrored.
motir-core/CLAUDE.md § 4-layer + the repo-owns-$queryRaw rule.