|
| 1 | +# Context: Docs Site SEO — leetcode-py |
| 2 | + |
| 3 | +Companion to a future `tasks.md` (checklist). This file holds everything an agent needs to plan SEO work: verified live findings, known bug classes, transferable decisions from the bakefile repo's completed SEO pass, and the opportunities specific to this repo. Dates are absolute. Verify anything marked "verify" against the live site before acting — this reflects 2026-08-24 state. |
| 4 | + |
| 5 | +## Project facts |
| 6 | + |
| 7 | +- Repo: `github.com/wislertt/leetcode-py`, main branch `main`. |
| 8 | +- Product: Python package that generates LeetCode practice environments (problem README, typed solution stub, parametrized pytest suite with 10+ cases, helpers, playground notebook) from JSON templates. |
| 9 | +- PyPI package name: `leetcode-py-sdk` (NOT `leetcode-py`). CLI: `lcpy`. |
| 10 | +- Scale: 307 problems under `leetcode/`, six collections (Grind 75, Grind, Blind 75, NeetCode 150, NeetCode 250, AlgoMaster 75). |
| 11 | +- Author: Wisaroot Lertthaweedech (`wisl.dev`). Same author as bakefile (`bakefile.wisl.dev`). |
| 12 | +- Docs: Mintlify site at `https://leetcode-py.wisl.dev` (custom domain; default deployment host `leetcode-py.mintlify.app`). |
| 13 | + |
| 14 | +## Docs stack and conventions |
| 15 | + |
| 16 | +- Mintlify, `docs/docs.json` at root of `docs/`. Theme `mint`. Site name `leetcode-py` (rendered title suffix is ` - leetcode-py`, 14 chars, so frontmatter titles must stay ≤~46 chars). |
| 17 | +- `docs/skill.md` is hand-written, served raw at `/skill.md`, overrides Mintlify's auto-generated one. Do not delete, no MDX-only components in it. |
| 18 | +- `markdown.instructions` in docs.json is injected into `llms.txt`, `llms-full.txt`, and Markdown page exports. |
| 19 | +- **Catalog pages are GENERATED** by `scripts/gen_catalog.py` (`docs/catalog/*.mdx` carry "GENERATED — do not edit" headers). Any change to catalog content = edit the generator, not the mdx. |
| 20 | +- Docs verification command: `bake docs-check` (runs `mintlify broken-links`). `bake docs` runs the dev server. Both defined in `bakefile.py`. |
| 21 | +- Examples policy: docs examples are backed by tests, copy verbatim from tested sources. |
| 22 | + |
| 23 | +## Verified live state (2026-08-24) |
| 24 | + |
| 25 | +Checked directly against production: |
| 26 | + |
| 27 | +- `robots.txt`: Mintlify default, clean. AI bots allowed, `Content-Signal: ai-train=yes, search=yes, ai-input=yes`. Do not replace. |
| 28 | +- `sitemap.xml`: auto-generated, 21 pages, fresh `lastmod`. |
| 29 | +- `llms.txt`: HTTP 200. |
| 30 | +- Canonical: set globally (`https://leetcode-py.wisl.dev`). |
| 31 | +- Organization schema with `sameAs` (GitHub, PyPI, wisl.dev). |
| 32 | +- PyPI `[project.urls]` links to docs site (dofollow backlink). |
| 33 | +- README links deeply into docs pages (collections, why-page, CLI guide). |
| 34 | + |
| 35 | +## Known bugs (same class as bakefile, verified live 2026-08-24) |
| 36 | + |
| 37 | +1. **Duplicated title tag.** Homepage renders `<title>leetcode-py - leetcode-py</title>` (page title + site name identical). Fix: give `docs/index.mdx` a keyword title, e.g. "LeetCode practice environments in Python" or similar; the suffix carries the brand. |
| 38 | +2. **og:image resolves to wrong host.** Meta emits `https://leetcode-py.mintlify.app/img/brand/og-card-light.png` (default deployment host) because `seo.metatags.og:image` in docs.json is a relative path. Fix: absolute URL `https://leetcode-py.wisl.dev/img/brand/og-card-light.png`. Verify the custom domain serves `/img/brand/*` (bakefile's did). |
| 39 | +3. **Product-label titles.** "Installation", "Quickstart", "Catalog", "Troubleshooting", "lcpy", "bakefile" (contributing) are labels, not search queries. Same fix pattern as bakefile: query-shaped titles + `sidebarTitle` for anything long. |
| 40 | + |
| 41 | +## Measurement status (head start — mostly done) |
| 42 | + |
| 43 | +- GSC **Domain property `wisl.dev` verified 2026-08-24** via DNS TXT at Spaceship registrar. A Domain property covers ALL subdomains, so `leetcode-py.wisl.dev` is already verified. No new verification needed. |
| 44 | +- Bing Webmaster imported from GSC same day (covers Bing + DuckDuckGo + Yahoo). |
| 45 | +- **Pending:** submit `https://leetcode-py.wisl.dev/sitemap.xml` in GSC (Sitemaps page) and confirm Bing copied it via import. |
| 46 | +- **Pending:** GSC baseline (~2 weeks after sitemap submit): record indexed pages, impressions, queries. |
| 47 | + |
| 48 | +## The big opportunity: 307 problem long-tail pages |
| 49 | + |
| 50 | +This repo has an asset bakefile does not: 307 problems whose names are high-volume search queries ("two sum python", "longest substring without repeating characters python solution"). Current state: |
| 51 | + |
| 52 | +- Catalog pages (`docs/catalog/blind-75.mdx` etc.) list problems but link them **offsite to GitHub** (`github.com/.../leetcode/two_sum/README.md`). All that content lives on github.com, not the docs domain. SEO value leaks offsite. |
| 53 | +- `leetcode/<problem>/README.md` per problem exists in-repo with rich content. |
| 54 | + |
| 55 | +Decision space (for the planning agent, not settled): |
| 56 | + |
| 57 | +- Generate per-problem docs pages from the same JSON/templates (mirror `gen_catalog.py` approach). 307 pages of real content, each targeting "[problem name] python". Mintlify scales fine; nav would need a hidden or collapsed section (`seo.indexing: "all"` exists for pages outside navigation). |
| 58 | +- Collection names are themselves high-volume keywords ("blind 75", "neetcode 150", "grind 75"). Those pages already exist — they mostly need title/description/intro strengthening, not creation. |
| 59 | +- Risks to weigh: thin-content pages if problem pages are just stubs, maintenance coupling to problem JSON. |
| 60 | + |
| 61 | +## Transferable decisions from the bakefile SEO pass (2026-08-24, same author, same Mintlify setup) |
| 62 | + |
| 63 | +Applied and verified on bakefile.wisl.dev — reuse the patterns: |
| 64 | + |
| 65 | +- Homepage/landing `title` frontmatter = keywords ("Python task runner, Makefile alternative"), site-name suffix carries brand. Never put the brand word in the title when the suffix already appends it. |
| 66 | +- `sidebarTitle` frontmatter decouples long SEO titles from sidebar labels. Mintlify supports it natively. |
| 67 | +- `og:image` must be absolute; relative resolves against the mintlify.app host. |
| 68 | +- Query-shaped H2s on comparison pages ("Make vs bakefile") match "X vs Y" queries. FAQ sections only with genuinely matching Q&A content. |
| 69 | +- Troubleshooting: split into per-error pages with the exact error string as title, hub page links all with error strings as anchor text. Behavioral notes stay on the hub. |
| 70 | +- Internal linking: no orphan pages (footer/sidebar links don't count — content links only), first-mention descriptive anchors, both directions between related pages. |
| 71 | +- Titles: unique, 50–60 chars rendered (including the ` - leetcode-py` suffix). |
| 72 | +- Verification: `bake docs-check` after every docs edit; `curl -s <url> | grep '<title>'` for rendered-title checks after deploy. |
| 73 | + |
| 74 | +## Off-repo SEO context (separate track, informational) |
| 75 | + |
| 76 | +- No blog on the docs site (author decision). Articles will live on wisl.dev (planned Astro blog) linking into both docs sites. Cross-posting to Medium/dev.to only with canonical → wisl.dev. |
| 77 | +- Backlinks create authority: awesome-list PRs, launch posts, GitHub topics, SO answers. |
| 78 | +- Both docs sites are subdomains of wisl.dev; the GSC Domain property covers them all. |
| 79 | + |
| 80 | +## Verification commands |
| 81 | + |
| 82 | +```bash |
| 83 | +bake docs-check # broken links |
| 84 | +curl -s https://leetcode-py.wisl.dev/ | grep '<title>' # rendered title |
| 85 | +curl -s https://leetcode-py.wisl.dev/ | grep 'og:image' # og image host |
| 86 | +curl -s https://leetcode-py.wisl.dev/sitemap.xml | grep -c '<loc>' # page count |
| 87 | +``` |
| 88 | + |
| 89 | +## Non-goals (decided, do not relitigate) |
| 90 | + |
| 91 | +- No blog section on the docs site. |
| 92 | +- No custom `robots.txt` / `sitemap.xml` (Mintlify defaults correct). |
| 93 | +- No structured-data changes beyond Mintlify's automatic JSON-LD + existing organization block. |
| 94 | +- Not moving docs off the subdomain. |
0 commit comments