Previously the only way to find someone to follow was knowing their
exact username. Add GET /api/v1/users/search (name/username ilike,
excludes blocked-either-way) and a /people page with debounced search
+ inline follow buttons. Linked from the Explore page.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- user_blocks table (composite PK), Block/Unblock button on profiles.
Blocking severs any existing follow relationship both ways and
prevents the blocked party from following, commenting on the
blocker's recipes, or the blocker from seeing their comments.
- reports table (recipe/comment/user targets, pending/reviewed/
dismissed status). ReportButton on comments, admin review queue at
/admin/reports with dismiss/mark-reviewed actions, audit-logged.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
DB/API already supported arbitrary-depth replies via the self-referencing
parentId, but the UI only rendered top-level + one reply level — a
reply-to-a-reply was fetched but never shown. Rewrite CommentItem as a
recursive component keyed off a parentId->children map; visual indent
caps at 4 levels (Reddit-style flatten) but nesting itself is unbounded.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Part of the social-feature backlog (follow, comments, reactions, ratings,
feed, threading) audited earlier — see conversation.
- notifications table: follow/comment/reply/reaction/rating events,
replaces the fully-dead feed_items table (feed_item_type enum existed
but had zero references anywhere in the codebase).
- Bell UI in the nav with unread badge, mark-all-read, 30s poll.
- Rate limiting on comment posting (20/min), follow/unfollow (30/min),
and comment reactions (60/min) — previously unthrottled.
- /recipes/[id] queried by (id, authorId=session.user) only, so any
recipe not owned by the viewer 404'd regardless of visibility.
Widen the query to include public/unlisted recipes and gate the
owner-only actions (edit, delete, version history, translate, AI
content generation) behind an isOwner check.
- user_follows had no primary key/unique constraint, so the follow
route's onConflictDoNothing() was a silent no-op — concurrent follow
clicks could insert duplicate rows and inflate follower counts. Add
a composite primary key on (follower_id, following_id).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Mobile:
- Recipes search bar full-width on mobile instead of capped narrow
- Cook mode ingredients panel stacks above the step instead of
squeezing it into a narrow column
- Version history Compare/Restore buttons wrap onto their own row
- Recipe edit ingredient fields wrap instead of forcing horizontal
scroll on narrow viewports
i18n: translates remaining hardcoded strings across recipes
filter/sort, adapt-recipe and AI variations dialogs, the full
settings section (sidebar + 6 sub-pages + BYOK/model-prefs/
API-keys/webhooks managers), explore tab, collections (new/fork/
share dialogs), meal planning (planner, AI generation phases, new
shopping list, shared-plan view), photo import, recipe bulk-select
toolbar, and recipe action-button tooltips. Also fixes the recipes
page subtitle, which wasn't just unworded but missing its {count}
interpolation entirely — it always rendered as the bare word
"results" regardless of how many recipes existed.
Feature: adds a ShareRecipeButton that copies the public /r/{id}
link to the clipboard, with a notice when the recipe isn't Public
yet.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Wires dozens of components and server pages to next-intl instead of hardcoded
English text, and adds a lightweight getMessages/formatMessage helper for
server components (print pages, public recipe page, cook metadata) since
next-intl/server isn't wired into this app's routing. Backfills missing
en/fr message keys that existing code already referenced but fr.json lacked.
Follow/unfollow users. Recipe favorites. Threaded comments with emoji reactions.
Collections (public/private) with shared member invite. Activity feed.
Public profile pages at /u/[username].