Skip to content

feat(landing): new landing page, /learn directory, and SEO/analytics repairs - #56

Merged
Tatenda merged 4 commits into
developfrom
chore/design-sync-flemoji-ui
Aug 4, 2026
Merged

feat(landing): new landing page, /learn directory, and SEO/analytics repairs#56
Tatenda merged 4 commits into
developfrom
chore/design-sync-flemoji-ui

Conversation

@Tatenda

@Tatenda Tatenda commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Three things, in three commits:

  1. chore(design-sync) — Claude Design sync inputs (pre-existing on this branch, not mine).
  2. feat(landing) — the landing-page revamp and public route restructure.
  3. fix(seo) — Search Console / analytics audit repairs.

Happy to split 2 and 3 into their own PRs if that reviews better.

Route changes

URL Serves
/ Marketing landing page (was the Learn hub)
/learn Learn directory — cluster hub
/learn?view=grid Article grid with cluster filters
/:slug Individual guide (was /learn/:slug)
/topic/:slug Topic hub (was /learn/topic/:slug)
/stream AI chat + streaming app (was /)

Old /learn/* URLs are kept alive by rewrites, not redirects, with canonicals pointing at the new root URLs — nothing 404s and search engines consolidate. /articles/:slug upgraded 307 → 308.

Production bug this fixes

NEXT_PUBLIC_SITE_URL in Vercel has a trailing newline, and resolveSiteUrl only stripped a trailing slash. Live production is currently serving:

sitemap.xml   <loc>https://flemoji.com\n/learn</loc>
robots.txt    Sitemap: https://flemoji.com\n/sitemap.xml

Every sitemap URL is malformed and robots.txt sitemap auto-discovery is dead. normalizeBaseUrl() now trims, so merging this fixes it without touching Vercel — though the env var is still worth cleaning up.

Other SEO/analytics fixes

  • Sitemap was submitting 8 unindexable URLs (six /genres/* 404s; /timeline + /league are noindex). Removed; added /topic/:slug, /privacy, /terms.
  • Reserved-slug guard — an article slugged tools would be shadowed by the static route, unreachable but still submitted.
  • Organization.logo pointed at a 404; WebSite.potentialAction declared a /search page that doesn't exist.
  • GA4 fired on localhost and every preview into the production property — now gated to production only.
  • GA4 received pageviews only; added sign_up, login, track_play.
  • Artist profiles had no metadata (Client Component) while being submitted to Google — added a segment layout.
  • /ai-test and /unauthorized were fully indexable — now noindex.
  • Logo asset replaced with the transparent version; every usage now inverts correctly on dark.

Verification

tsc 0 errors · lint 0 errors · jest 337/337 across 28 suites (11 new tests: reserved slugs, SITE_URL whitespace, tool registry drift).

Verified against the running app at 1440px and 390px, light and dark.

Known gaps

  • No consent management for GA4 (POPIA/GDPR) — needs a product decision.
  • Local DB has no published articles or verified artists, so /:slug and /artist/:slug were exercised via 404/metadata paths, not with real content.

🤖 Generated with Claude Code

Tatenda and others added 3 commits August 4, 2026 14:54
Syncs src/components/ui/ to claude.ai/design as the "Flemoji Design System"
project: 17 visual primitives, each with an authored, render-verified preview.

What's here:
- assets/ds-entry.ts   scoped bundle entry (primitives only, no next/navigation
                       or react-image-crop; also re-exports SelectItem, without
                       which FSelect is unusable)
- assets/ds.css + tailwind.ds.js + build-css.sh
                       compiles the DS stylesheet. Defines the three
                       --font-* custom properties next/font injects at runtime,
                       and safelists the documented brand palette, which Tailwind
                       would otherwise purge (bg-primary-700, bg-secondary-600,
                       shadow-glow et al were all missing).
- assets/fonts.css + woff2s
                       Inter / Poppins / JetBrains Mono harvested from the
                       next/font build, so designs render in brand type.
- previews/*.tsx       17 authored preview cards, all graded good
- conventions.md       the header inlined into the design agent's prompt;
                       every component and class name in it was verified
                       against the built bundle
- NOTES.md             re-sync instructions, gotchas, risks

Note for the team: docs/design-system.md is stale — it documents the
pre-efc251c purple-primary tokens. conventions.md reflects what actually
ships (primary blue, secondary purple) and the doc is deliberately not
uploaded so it can't mislead the design agent.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Implements the Claude Design handoff ("Landing page redesign: three
directions" → Flemoji Landing Page.dc.html) and restructures public routes
around it.

Routes:
  /                 marketing landing page (was the Learn hub)
  /learn            Learn directory — cluster hub
  /learn?view=grid  paginated article grid with cluster filters
  /:slug            individual guide (was /learn/:slug)
  /topic/:slug      topic hub (was /learn/topic/:slug)
  /stream           AI chat + streaming app (was /)

Old /learn/:slug and /learn/topic/:slug URLs are kept alive by rewrites in
next.config.mjs rather than redirects, so existing links keep working while
each page's canonical points at the new root URL — search engines consolidate
without anything 404ing. /articles/:slug now uses permanentRedirect (308) so
ranking signals actually transfer.

The landing page is built from real data: guides from article-service, tools
from the registry, and the five most-played public tracks via a new
MusicService.getFeaturedTracks(). Sections live in src/components/home/ with
shared values in tokens.ts. The equaliser is pure CSS (with a
prefers-reduced-motion guard) so the whole page stays a Server Component.

Two deliberate deviations from the mock: the stream play button links to
/stream instead of toggling a decorative playing state, and every section has
dark-mode variants since the header exposes a live theme toggle.

Also replaces public/main_logo.png with the transparent-background version.
The old file was opaque RGB with a baked-in white background, which rendered
as a solid white block on every dark surface — including the purple gradient
heroes. Because it is now transparent the dark wordmark is invisible on dark
backgrounds unless inverted, so every usage that lacked dark handling gained
`dark:brightness-0 dark:invert`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…uilding

Findings from a Search Console / analytics audit, all verified against the
running app.

SITE_URL was not whitespace-safe. NEXT_PUBLIC_SITE_URL is set in Vercel with a
trailing newline (the usual `echo … | vercel env add`), and resolveSiteUrl only
stripped a trailing slash, so production shipped:

  sitemap.xml   <loc>https://flemoji.com\n/learn</loc>
  robots.txt    Sitemap: https://flemoji.com\n/sitemap.xml

Every sitemap URL was malformed and robots.txt sitemap auto-discovery was dead.
Metadata canonicals hid it because Next normalises those through new URL();
the raw interpolations did not. normalizeBaseUrl() now trims, covering both env
sources, with regression tests.

Sitemap submitted 8 unindexable URLs: six /genres/* entries whose route was
never built (all 404), and /timeline + /league, which set robots noindex.
Removed both groups, added /topic/:slug (clusters with published articles only)
plus /privacy and /terms.

Guides now live at the root, so an article slugged `tools` or `learn` is
shadowed by that static route — unreachable, yet still submitted, and emitted
twice. Next always prefers a static segment, so this is blocked at write time
via RESERVED_ROOT_SLUGS in createArticle/updateArticle, with the sitemap
filtering defensively for rows written before the guard.

Structured data claimed two URLs that 404: Organization.logo pointed at
/logo.png (the asset is main_logo.png) and WebSite.potentialAction declared a
sitelinks searchbox at /search, which does not exist. Fixed the first, removed
the second.

GA4 fired on localhost and on every preview deploy into the production
property. It is now gated on NEXT_PUBLIC_VERCEL_ENV === 'production' and the
measurement id is overridable. The property also only ever received automatic
pageviews, so sign_up, login and track_play events are now emitted through a
typed helper that no-ops when the tag is absent.

Artist profiles are Client Components and could not export metadata, so every
one inherited the site title with no description or canonical while being
submitted via sitemap. Added a segment layout with generateMetadata that uses
its own read-only query — ArtistService.getArtistBySlug increments profileViews
as a side effect and would have double-counted every crawl.

Also: /ai-test and /unauthorized were fully indexable and are now noindex
(deliberately not robots.txt Disallow, which would stop Google reading the
noindex); added canonicals to /privacy and /terms; added a drift guard between
the tool registry and ToolRenderer's import map, since registering a tool
without wiring the renderer publishes a 200 page with an empty body; and
documented the SEO/analytics env vars, which .env.example never mentioned.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
music-next Error Error Aug 4, 2026 2:54pm

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 58e21a97-e870-4b15-8f58-2fa1bf4c46df

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

The Claude Design sync inputs are generated bundles — compiled CSS, subset
woff2 fonts, preview HTML — not hand-authored source. `prettier --check .`
flagged three CSS files and failed the "Type-check, lint, format" CI job,
blocking the branch. Same treatment `.claude/` and `.cursor/` already get.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Tatenda
Tatenda merged commit bd102cf into develop Aug 4, 2026
4 of 5 checks passed
@Tatenda
Tatenda deleted the chore/design-sync-flemoji-ui branch August 4, 2026 18:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant