feat: clear chat history manually, auto-expire old history after 90 days

Manual: DELETE /api/v1/ai/chat-history (scoped by recipeId or scope=general,
matching GET's scoping) plus a trash-icon button + confirm dialog in both
chat panels' headers.

Automatic: new internal cron endpoint (chat-cleanup), same shared-secret
pattern as the existing leftover-reminders/weekly-digest crons, deletes
any chat_messages older than 90 days. Wired into cron/crontab (daily,
03:00 UTC) and the Dockerfile's cron stage.

Verified locally: cleared a real conversation through the actual UI and
confirmed it didn't come back on reopen (not just cleared client-side);
inserted a 100-day-old and a 5-day-old message directly, called the cron
endpoint with the real shared-secret check, confirmed only the old one
was deleted and the recent one survived; confirmed the endpoint 401s with
no/wrong secret.
This commit is contained in:
Arnaud
2026-07-12 23:27:05 +02:00
parent 9549684254
commit adaa837564
10 changed files with 200 additions and 5 deletions
@@ -9,6 +9,7 @@ import { MessageCircle, Send, Bot, User } from "lucide-react";
import ReactMarkdown from "react-markdown";
import { cn } from "@/lib/utils";
import { ChatHistorySearch } from "./chat-history-search";
import { ClearChatHistoryButton } from "./clear-chat-history-button";
type Message = {
role: "user" | "assistant";
@@ -105,7 +106,10 @@ export function RecipeChatPanel({ recipeId, recipeTitle }: Props) {
<Bot className="h-4 w-4 text-primary" />
{t("title")}
</SheetTitle>
<ChatHistorySearch recipeId={recipeId} />
<div className="flex items-center gap-0.5">
<ChatHistorySearch recipeId={recipeId} />
<ClearChatHistoryButton recipeId={recipeId} disabled={messages.length === 0} onCleared={() => setMessages([])} />
</div>
</div>
<p className="text-xs text-muted-foreground text-left">{recipeTitle}</p>
</SheetHeader>