Skip to content

feat: search, tags, RSS and SEO files - #4

Merged
Mimic890 merged 5 commits into
mainfrom
feat/search-seo
Nov 4, 2026
Merged

Mimic890 merged 5 commits into
mainfrom
feat/search-seo

Conversation

@Mimic890

@Mimic890 Mimic890 commented Nov 4, 2026

Copy link
Copy Markdown
Owner

Stage 4: search, tags, RSS and SEO files.

Changes

  • Search: Bleve v2.6.1, in-memory index rebuilt on sync. en and ru analyzers by post lang. Field boosts: title > tags > description > body. Fuzziness depends on word length (0 / 1 / 2), plus prefix match on the last word. Query is built in code, capped at 200 characters and 10 terms. Snippets are sanitized down to <mark>.
  • GET /search?q=&tag=&page= works without JS and has noindex. static/search.js swaps the results while you type (debounced, history.replaceState).
  • Tags: lower case, Obsidian characters, 1–50 characters, at most 20 per post. /tags/<tag> is paginated. Chips on cards and posts use 24 hash-based hue buckets. A test checks WCAG AA contrast (≥ 4.5) for every bucket in both themes.
  • RSS /rss.xml:
    • full HTML in content:encoded, with absolute URLs;
    • dc:creator from AUTHOR_NAME;
    • atom:updated and atom:link rel=self.
  • SEO:
    • meta description, canonical, Open Graph and Twitter card (cover, else DEFAULT_OG_IMAGE);
    • JSON-LD BlogPosting from json.Marshal;
    • /sitemap.xml, /robots.txt, /llms.txt, /posts/<slug>.md, /<INDEXNOW_KEY>.txt.
  • Images: width/height are read from the mirror (PNG, JPEG, GIF, WebP via golang.org/x/image, SVG). Any asset change re-renders all posts.
  • IndexNow: one ping per sync with new, changed and removed post URLs. No ping on the first index load.
  • Config:
    • new AUTHOR_NAME (default SITE_NAME);
    • DEFAULT_OG_IMAGE must be a file inside assets/;
    • INDEXNOW_KEY format is checked.
  • SPEC.md and SPEC.ru.md: config table, tag rules, endpoint table and Decision log updated.

Checks

  • go vet, staticcheck, govulncheck and go test -race all pass. govulncheck reports one golang.org/x/crypto advisory in a module, but our code does not call it.
  • Fuzz runs of 30–45 s each, all clean: FuzzSearch, FuzzSVGSize, FuzzParse.
  • Smoke test against Garage behind Caddy, in headless Chrome:
    • home, post, tag and search pages, light and dark, desktop and mobile;
    • live search updates results with no console errors;
    • RSS, sitemap, robots, llms and .md checked with curl.

Not checked

  • No real IndexNow request was sent. A fake server in the tests covers it.
  • RSS has not been run through an external feed validator.
  • RATE_LIMIT_SEARCH comes in stage 5. /search is unlimited until then; the code has a shortcut: comment.

@Mimic890
Mimic890 merged commit 923b61a into main Nov 4, 2026
4 checks passed
@Mimic890
Mimic890 deleted the feat/search-seo branch November 4, 2026 06:31
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