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
This commit is contained in:
2026-10-27 11:35:25 +01:00
parent 163b0aaf98
commit 6eb6cb7a4d
18 changed files with 997 additions and 15 deletions

View File

@@ -0,0 +1,32 @@
package updates
import (
"github.com/go-gormigrate/gormigrate/v2"
"gorm.io/gorm"
)
// createNotFound creates golem15_seo_notfound: the 404 log (D-20), one row
// per address.
var createNotFound = []*gormigrate.Migration{
{
ID: "202610270007_create_golem15_seo_notfound",
Migrate: func(tx *gorm.DB) error {
return tx.Exec(`CREATE TABLE golem15_seo_notfound (
id BIGSERIAL PRIMARY KEY,
url TEXT NOT NULL,
hits BIGINT NOT NULL DEFAULT 1,
first_seen TIMESTAMP(0) NULL,
last_hit TIMESTAMP(0) NULL,
referer TEXT NOT NULL DEFAULT '',
CONSTRAINT golem15_seo_notfound_url UNIQUE (url)
)`).Error
},
Rollback: func(tx *gorm.DB) error {
return tx.Exec(`DROP TABLE IF EXISTS golem15_seo_notfound`).Error
},
},
}
func init() {
Register(createNotFound...)
}