feat: per-category email prefs, admin ops webhooks, per-user feature toggles (v0.61.0)

- Notification email preferences: every push category (follow, comment,
  reply, reaction, rating, mention, leftoverExpiring, shoppingList) now has
  an independent email toggle, plus a Weekly Digest toggle. Previously email
  sent unconditionally whenever the recipient had one; now gated the same
  way push already was. The weekly-digest cron route excludes opted-out
  users.

- Admin-only site-wide webhooks (Admin → Webhooks): new signups, support
  tickets, and reports filed can now fire an HMAC-signed HTTP webhook
  (Slack/Discord/ops alerting), independent of the existing per-user
  webhooks (which stay scoped to a user's own recipe/meal-plan/shopping-list
  events). Signing/delivery logic factored into lib/webhook-delivery.ts and
  shared by both dispatchers instead of duplicated.

- Settings → Features: users can hide Nutrition, Pantry, Meal Plan,
  Shopping Lists, Collections, or Messages from their own nav. Purely
  cosmetic — hidden pages stay reachable by direct link, nothing is
  access-restricted.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Arnaud
2026-07-20 23:07:28 +02:00
parent cced962bff
commit c5e1643d39
40 changed files with 18383 additions and 79 deletions
+23 -2
View File
@@ -415,6 +415,7 @@
"security": "Security",
"aiModels": "AI & Models",
"notifications": "Notifications",
"features": "Features",
"nutrition": "Nutrition",
"apiKeys": "API Keys",
"webhooks": "Webhooks",
@@ -1399,7 +1400,9 @@
"settingsForm": {
"notificationCategories": {
"title": "Notification categories",
"description": "Choose which push notifications you want to receive.",
"description": "Choose which notifications you want to receive, and whether by push, email, or both.",
"push": "Push",
"email": "Email",
"follow": "New followers",
"comment": "Comments on your recipes",
"reply": "Replies to your comments",
@@ -1407,7 +1410,25 @@
"rating": "Ratings on your recipes",
"mention": "Mentions in comments",
"leftoverExpiring": "Leftovers expiring soon",
"shoppingList": "Shared shopping list updates"
"shoppingList": "Shared shopping list updates",
"weeklyDigest": "Weekly digest",
"weeklyDigestDescription": "A weekly email summary of new followers, comments, and ratings, plus trending recipes."
},
"featureToggles": {
"title": "Features",
"description": "Hide features you don't use from your navigation. This only affects your own view — hidden pages stay reachable by direct link, nothing is deleted.",
"nutrition": "Nutrition",
"nutritionDescription": "Nutrition diary and goals.",
"pantry": "Pantry",
"pantryDescription": "Track what you have on hand.",
"mealPlan": "Meal Plan",
"mealPlanDescription": "Weekly meal planning.",
"shoppingLists": "Shopping Lists",
"shoppingListsDescription": "Shared shopping lists.",
"collections": "Collections",
"collectionsDescription": "Organize recipes into collections.",
"messages": "Messages",
"messagesDescription": "Direct messages with other cooks."
},
"profile": "Profile",
"changePhoto": "Change photo",
+23 -2
View File
@@ -415,6 +415,7 @@
"security": "Sécurité",
"aiModels": "IA et modèles",
"notifications": "Notifications",
"features": "Fonctionnalités",
"nutrition": "Nutrition",
"apiKeys": "Clés API",
"webhooks": "Webhooks",
@@ -1390,7 +1391,9 @@
"settingsForm": {
"notificationCategories": {
"title": "Catégories de notifications",
"description": "Choisissez les notifications push que vous souhaitez recevoir.",
"description": "Choisissez les notifications que vous souhaitez recevoir, par push, par e-mail, ou les deux.",
"push": "Push",
"email": "E-mail",
"follow": "Nouveaux abonnés",
"comment": "Commentaires sur vos recettes",
"reply": "Réponses à vos commentaires",
@@ -1398,7 +1401,25 @@
"rating": "Notes sur vos recettes",
"mention": "Mentions dans les commentaires",
"leftoverExpiring": "Restes bientôt périmés",
"shoppingList": "Mises à jour des listes de courses partagées"
"shoppingList": "Mises à jour des listes de courses partagées",
"weeklyDigest": "Résumé hebdomadaire",
"weeklyDigestDescription": "Un résumé hebdomadaire par e-mail des nouveaux abonnés, commentaires et notes, ainsi que des recettes tendance."
},
"featureToggles": {
"title": "Fonctionnalités",
"description": "Masquez les fonctionnalités que vous n'utilisez pas de votre navigation. Cela n'affecte que votre propre vue — les pages masquées restent accessibles par lien direct, rien n'est supprimé.",
"nutrition": "Nutrition",
"nutritionDescription": "Journal et objectifs nutritionnels.",
"pantry": "Placard",
"pantryDescription": "Suivez ce que vous avez sous la main.",
"mealPlan": "Planning de repas",
"mealPlanDescription": "Planification hebdomadaire des repas.",
"shoppingLists": "Listes de courses",
"shoppingListsDescription": "Listes de courses partagées.",
"collections": "Collections",
"collectionsDescription": "Organisez vos recettes en collections.",
"messages": "Messages",
"messagesDescription": "Messages directs avec d'autres cuisiniers."
},
"profile": "Profil",
"changePhoto": "Changer la photo",