Commit Graph

19 Commits

Author SHA1 Message Date
b3981614cb docs: robots.txt, AI bots and verification files in README
- redirects, address changes, the 404 log and its report endpoint, URL
  normalisation, strict URLs and the redirect decision of resolve
- robots.txt, AI bots, verification files, the new config keys and the
  grobotstxt dependency
2026-10-27 11:54:02 +01:00
ec74062624 feat: verification files API
- GET /_seo/api/v1/verification/{name} serves a verification file stored
  in the SEO settings with its content type, nosniff and a sandboxing CSP
  (D-05, D-103); the name pattern is enforced in the route and the
  lookup, and no route is registered at the site root
2026-10-27 11:52:55 +01:00
51413fbda4 feat: robots.txt editor and tester screen
- golem15.seo.robots singleton (UI-SPEC C10): staging callout and the
  served file (P4); the plugin's own extension adds the editor, the
  tester and the AI bots tab, saved to the robots row with history
- field type robotstxt (E4, live lint, size meter; Decode refuses over
  500 KB) and widget golem15-seo-robotstester (E5) on robots_test, which
  tests the unsaved text and switches through grobotstxt
- saving rules that block a noindex address answers robots.blocks_noindex
2026-10-27 11:51:41 +01:00
3dd936202f feat: robots.txt served file, AI bots and the non-production lock
- github.com/jimsmart/grobotstxt v1.0.3 (D-99, decision note in the
  framework repo)
- golem15_seo_robots singleton: rules and AI bot switches; eleven bots
  incl. Claude-User, all allowed by default
- GET /robots.txt: rules, a Disallow group per switched-off bot and the
  golem15.seo.robots_sitemaps lines; outside production the lock with
  X-Robots-Tag; never a 5xx (last good body, else allow-all)
- TestRobots on Google's matcher with the deciding line, and the
  noindex-blocked check (D-24)
2026-10-27 11:45:44 +01:00
4cb0fbfebb feat: URL normalisation, strict URLs and the one-hop redirect decision
- Normalize: https, www or bare host, double slashes and index files,
  trailing slash add/remove, optional ASCII lowercasing (defaults change
  nothing but scheme, slashes and index files)
- strict URLs through signpost MatchPath: a path that names a record
  without being its address 301s to the record's address
- resolve runs normalisation, redirects, strict URLs, then SEO; the
  location is the final address, so a visitor makes one hop
- P1 warns when a record's canonical URL redirects
2026-10-27 11:41:45 +01:00
327925c43e feat: address-change redirects for writes outside the admin
- the RecordSaved listener re-describes an updated record of a content
  type after commit and applies AddressChanged per changed locale, so
  Journal's API, MCP and imports get the 301 too; an admin save that
  already applied it changes nothing more
2026-10-27 11:37:20 +01:00
6eb6cb7a4d feat: 404 log and report endpoint
- POST /_seo/api/v1/notfound with the golem15.seo.notfound_token bearer
  (constant-time, off when unset), URL and referer caps, a row cap with
  an hourly warning, throttle bucket seo-notfound
- golem15.seo.notfound list by hits with Resolved rows, a preview with the
  resolved hint, a prompted 301 and a 410 record action, a bulk 410 that
  refuses a selection with a covered address
- every /_seo/api/v1 answer carries X-Robots-Tag: noindex
2026-10-27 11:35:25 +01:00
163b0aaf98 feat: redirects screen
- golem15.seo.redirects list and form (UI-SPEC C8): chain rows marked,
  status, match, origin and chain filters, the navigation item lands here
- a field-less extension on the controller refuses a loop with
  redirects.loop on target, answers the chain notice and records history
- the status dropdown posts text, read through RedirectStatus
2026-10-27 11:30:56 +01:00
34a65b846e feat: redirect engine with loop refusal and chain notices
- rule set: exact sources by key, patterns by literal prefix, regex by id
  (stdlib RE2, compiled once per source); ignore case, trailing slash,
  query ignore/pass, a source with ? matches its query exactly
- targets: captures escaped, a relative target never leaves the site, an
  absolute one keeps its host
- SaveRedirect validates, simulates the rule in place (exact, pattern and
  regex probes, 10 hops) and refuses a loop; chains answer the notice
- resolve follows the chain to its final target, 410 answers gone, a
  runtime cycle answers not_found and is logged once
2026-10-27 11:26:42 +01:00
e31ac7c1c6 feat: address-change 301 (tracer)
- golem15_seo_redirects table and Redirect model
- AddressChanged: old -> new 301 in the save transaction, earlier
  redirects pointed at the new address, self-loops dropped
- the SEO tab save compares descriptor URLs with the entry URLs and
  answers the redirects.auto_created notice
- resolve answers redirect with the absolute target for an exact source
2026-10-27 11:20:59 +01:00
b38eb4bf66 docs: plugin README 2026-10-27 11:04:42 +01:00
93ddbcc9ef feat: SEO field types and the complete SEO tab 2026-10-27 11:04:03 +01:00
deebd9aa65 feat: SEO field elements and bundle 2026-10-27 10:53:59 +01:00
ab8905c429 feat: entry generation job and cleanup on delete 2026-10-27 10:48:02 +01:00
e8a6b9fc77 feat: SEO change history 2026-10-27 10:45:30 +01:00
9f1082d62d feat: full precedence resolver with value sources 2026-10-27 10:39:55 +01:00
30edb8adee feat: per-type settings tabs and the SEO tab permission 2026-10-27 10:36:32 +01:00
ce60c8a1ee feat: URL rules and the settings singleton 2026-10-27 10:34:39 +01:00
fb9590f099 feat: plugin scaffold, entries and the SEO tab tracer 2026-10-27 10:27:46 +01:00