✨ feat: catalog navigation rework, wanted skills, onboarding + newsletter prefs#97
Merged
Merged
Conversation
…tter prefs Navigation and discovery: - Rework home page: new hero, linked catalog stat line, catalog-wide full-text search (/api/search/quick) with grouped results, topic quick-nav chips, explore-card grid into every section - New browse pages: /issues (tag + SDG + sort filters), /solutions (status filter), /case-studies (outcome/scale/semantic filters), /tags (usage-ranked topic index), /map (fullscreen map of all geolocated content with layer toggles) - New endpoints: /api/stats, /api/map, /api/solutions, /api/search/quick; sdg filter on /api/issues; usage counts on /api/tags and /api/sdgs - Minimal redesign of case-study cards; solution cards drop irrelevant sub-issue/solution chips; sitemap + SEO for new pages - Mobile responsiveness pass across public pages Community features: - Wanted skills on issues/solutions: schema + unique index, CRUD endpoints, node-page section with social share, contribute card - Contribute page rework with always-on ways to help - Onboarding flow (/onboarding): skills, free-text interests with embedding-based topic preview (/api/tags/similar), newsletter opt-in with frequency + content preferences - user_interests (vector embeddings + HNSW index), newsletter_prefs, users.onboarded_at; settings sections for interests + newsletter Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ared scaleBadgeLabel helper
🧹 Code quality
updated for |
Typecheck (vue-tsc):
- Widen useUmami track() data type to accept boolean | undefined so
event props like { enabled, on, newsletter } and conditional
{ tag: x || undefined } type-check (NewsletterPrefs, map, onboarding,
issues pages).
- contribute.vue: type help-label counts as Record<string, number> and
guard LABEL_META[activeLabel]?.hint under noUncheckedIndexedAccess.
Formatting (vize fmt): reformat files flagged by format:check
(admin logs handler wrap + drizzle migration meta trailing newlines).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Escape user-derived values in revision notification emails (shared
escapeHtml util, also reused by the OAuth consent page)
- Guard the revision approve compensation and make post-apply
snapshot/audit writes loud-but-best-effort (never revert an applied
revision to pending — that would allow a double apply)
- Exclude rejected case studies from the me/overview counter
- Add missing DB CHECK constraints for revisions.ai_verdict,
revisions.decided_by_role, and newsletter_prefs.frequency
- /api/case-studies now returns { items, degraded } so clients can tell
when a semantic query fell back to recency; surface it on the page
- Remove forbidden data-umami-event attributes; use useUmami() instead
of the bare umami global in appeal handlers
- Clear debounce timers on unmount; skip empty-query quick search on
homepage first paint
- Fix tests: assert the intended most_voted default sort, make
similar.test.ts actually exercise the endpoint (summary, not
description), and turn the stale issue-detail moderation-fields test
into a privacy regression test
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Clickable stepper with sharp progress bars and live count chips, personalized greeting, icon tiles + ghost step numerals on cards, tap-to-fill skill examples, back navigation with direction-aware transitions, ?step= URL sync, auto-add of typed-but-unsubmitted skills on continue, and a completion panel with next-step CTAs instead of an instant redirect. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Deduplicate the issue/solution list queries (issue-list.ts), route-param and node-lookup guards (route-guards.ts), and parent counter updates (issue-counters.ts, shared with the moderation worker), and spread a common timestamps pair across the schema tables. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
….css The three map components carried identical :deep(.leaflet-control-zoom) overrides; hoist them into one global stylesheet. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Weekly/monthly digest emails for opted-in users, sent by cron tasks (Mondays / 1st of month, 8am UTC): - newsletter-digest.ts assembles per-run sections (good news, help wanted, product updates) once and per-user sections (interest matches via pgvector, skill matches vs recent wanted skills) per recipient; empty digests are never sent - newsletter-send.ts mirrors compute:trust-scores (chunked, per-user failures isolated) with a lastSentAt column guarding cron retries - dashboard-bento email template (rounded cards on gray, Oswald caps, chips, blue pill button) with a plaintext twin; all user content escaped - HMAC-token unsubscribe endpoint that works logged-out, linked from every footer - sendEmail now works without an h3 event: the cloudflare:scheduled hook stashes the EMAIL binding for tasks Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Eliminate all 6 fallow clone groups: - add requireEventContext/loadIssueOr404 to route-guards, shared by the 5 issue/case-study moderation handlers - extract formatRelative into app/utils/relative-time.ts (4 call sites) - extract cleanLinkRows into app/utils/link-rows.ts (6 call sites) Also reformat the two drizzle-generated migration meta files that were failing vize fmt --check. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drizzle rewrites the snapshot/journal JSON in its own format on every db:generate, so scanning them just makes a new migration fail fmt --check. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
mathix420
marked this pull request as ready for review
July 13, 2026 12:41
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.
What
Three related workstreams, built from a content scan of the production catalog (130 geolocated case studies, 72 solutions, 64 issues, 122 tags — almost none of it reachable from the old single-list home page).
Navigation & discovery
/api/search/quick, grouped issue/solution/case-study results), topic quick-nav chips, explore-card grid into every section/issues(search + tag + SDG + sort),/solutions(status filter),/case-studies(outcome / scale / semantic query),/tags(usage-ranked index),/map(fullscreen map of all geolocated content with layer toggles)/api/stats,/api/map,/api/solutions,/api/search/quick;sdgfilter on/api/issues; usage counts on/api/tagsand/api/sdgs; case-study limit cap raised to 50Wanted skills (demand side of skill matching)
wanted_skillstable (case-insensitive unique per node, custom migration 0007) + CRUD endpoints under/api/issue/:id/wanted-skillsOnboarding + newsletter preferences
/onboardingflow shown once after signup: skills, free-text interests, newsletter opt-in (frequency + content flags: good news, skill matches, topic matches, help wanted)user_interests.embedding(HNSW index, custom migration 0008), with a live "targets these topics" preview via/api/tags/similarnewsletter_prefs,users.onboarded_at, settings sections for both; sending pipeline deliberately out of scopeMigrations
0019–0021(drizzle) + custom0006_help_labels_indexes,0007_wanted_skills_unique,0008_user_interests_indexes. Applied and verified locally.Testing
tests/api/Notes for review
tests/apifailures (issue-detail moderation fields, default sort, similar too_short) predate this branch🤖 Generated with Claude Code