feat(notifications): durable per-user inbox (P1) + maintenance schema

Add a server-backed notification center that coexists with the client-side
transient bell: a per-user `notifications` table (type/title/body/data JSON/
read/dismissed), a `/api/me/notifications` CRUD API (list, unread_count, read,
read_all, dismiss, clear), and a left-nav inbox module with a live unread badge
polled via useLiveQuery. Known types render trilingual text from type+data
(English stored text is the fallback); read rows are trimmed past a soft cap.

Also adds the schema the maintenance job builds on: videos.list?part=status
columns (embeddable/privacy_status/upload_status) and the validation lifecycle
columns (last_checked_at, unavailable_since, unavailable_reason).

Page-id validation is centralized in one PAGES source of truth (isPage) so the
new page survives reload without a second allowlist to keep in sync.
This commit is contained in:
npeter83 2026-06-18 03:20:17 +02:00
parent a11a8db278
commit b9a3a9012d
14 changed files with 649 additions and 22 deletions

View file

@ -0,0 +1,16 @@
{
"navLabel": "Benachrichtigungen",
"title": "Benachrichtigungen",
"subtitle": "Neuigkeiten aus deiner Bibliothek und vom System.",
"empty": "Alles erledigt.",
"markAllRead": "Alle als gelesen markieren",
"clearAll": "Alle löschen",
"markRead": "Als gelesen markieren",
"dismiss": "Verwerfen",
"andMore": "und {{count}} weitere",
"maintenance": {
"title": "Videos entfernt",
"body_one": "{{count}} gespeichertes oder in einer Playlist befindliches Video wurde entfernt, weil es auf YouTube nicht mehr verfügbar ist.",
"body_other": "{{count}} gespeicherte oder in Playlists befindliche Videos wurden entfernt, weil sie auf YouTube nicht mehr verfügbar sind."
}
}

View file

@ -0,0 +1,16 @@
{
"navLabel": "Notifications",
"title": "Notifications",
"subtitle": "Updates from your library and the system.",
"empty": "You're all caught up.",
"markAllRead": "Mark all read",
"clearAll": "Clear all",
"markRead": "Mark read",
"dismiss": "Dismiss",
"andMore": "and {{count}} more",
"maintenance": {
"title": "Videos removed",
"body_one": "{{count}} saved or playlisted video was removed because it's no longer available on YouTube.",
"body_other": "{{count}} saved or playlisted videos were removed because they're no longer available on YouTube."
}
}

View file

@ -0,0 +1,16 @@
{
"navLabel": "Értesítések",
"title": "Értesítések",
"subtitle": "Frissítések a könyvtáradból és a rendszertől.",
"empty": "Nincs új értesítés.",
"markAllRead": "Összes olvasott",
"clearAll": "Összes törlése",
"markRead": "Olvasottnak jelöl",
"dismiss": "Elvetés",
"andMore": "és még {{count}}",
"maintenance": {
"title": "Videók eltávolítva",
"body_one": "{{count}} mentett vagy lejátszási listás videó eltávolítva, mert már nem elérhető a YouTube-on.",
"body_other": "{{count}} mentett vagy lejátszási listás videó eltávolítva, mert már nem elérhetők a YouTube-on."
}
}