Add personalization, outbound feeds, and PWA/push to the web UI

A multi-session build turning Pete's read-only web UI into something people
return to. Five phases, signed-in features keyed off the OIDC subject; anonymous
visitors keep the reverse-chron feed and localStorage-only state.

Phase 1 — per-user read + bookmark state: user_story_state table +
storage/userstate.go; auth-gated /api/read, /api/bookmark, /api/state and a
/bookmarks page; reader.js syncs state server-side for signed-in users. Also
hides the Matrix-posting UI when posting.enabled=false (web-only mode).

Phase 2 — outbound feeds: storage.ListForFeed + web/feed.go hand-build RSS 2.0
(content:encoded) and JSON Feed 1.1 (no new dep); /feed.xml, /feed.json and
per-channel variants; <link rel=alternate> discovery tags.

Phase 3 — "For you" + related: storage/rank.go scores recent unread candidates
by channel/source affinity + recency decay; RelatedStories via FTS5. ForYou rail
+ /for-you page; public /api/related feeds the reader's "You might also like".

Phase 4 — source-health dashboard: source_health table + storage/sourcehealth.go
(RecordPollResult, ListSourceHealth, SourceContentStats), written by the poller;
admin-gated /status page behind web.admin_subs.

Phase 5 — PWA + offline reader + Web Push: root-scoped manifest.webmanifest and
sw.js (app-shell precache, /api/article runtime cache for offline reading,
offline fallback, push/notificationclick handlers); PNG icons from pete.avif;
pwa.js registers the SW and drives a notifications toggle. Web Push adds
webpush-go, a [web.push] config block (pete -genvapid mints VAPID keys), a
push_subscriptions table, auth-gated subscribe/unsubscribe endpoints, and a
digest sender that pings each subscriber "N new stories" past their watermark,
honoring disabled-sources and pruning gone endpoints.

Tests added beside each new storage/web file; go test ./... and go vet clean.
This commit is contained in:
prosolis
2026-07-07 00:07:19 -07:00
parent 55aa167151
commit 71f7050f41
45 changed files with 3622 additions and 36 deletions

10
go.mod
View File

@@ -5,7 +5,12 @@ go 1.25.0
require (
github.com/BurntSushi/toml v1.6.0
github.com/PuerkitoBio/goquery v1.12.0
github.com/SherClockHolmes/webpush-go v1.4.0
github.com/coreos/go-oidc/v3 v3.19.0
github.com/mmcdole/gofeed v1.3.0
go.mau.fi/util v0.9.9
golang.org/x/image v0.41.0
golang.org/x/oauth2 v0.36.0
maunium.net/go/mautrix v0.28.0
modernc.org/sqlite v1.50.1
)
@@ -13,9 +18,9 @@ require (
require (
filippo.io/edwards25519 v1.2.0 // indirect
github.com/andybalholm/cascadia v1.3.3 // indirect
github.com/coreos/go-oidc/v3 v3.19.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/go-jose/go-jose/v4 v4.1.4 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
@@ -32,12 +37,9 @@ require (
github.com/tidwall/match v1.2.0 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
go.mau.fi/util v0.9.9 // indirect
golang.org/x/crypto v0.52.0 // indirect
golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a // indirect
golang.org/x/image v0.41.0 // indirect
golang.org/x/net v0.55.0 // indirect
golang.org/x/oauth2 v0.36.0 // indirect
golang.org/x/sys v0.45.0 // indirect
golang.org/x/text v0.37.0 // indirect
modernc.org/libc v1.72.3 // indirect